| //===- CXType.cpp - Implements 'CXTypes' aspect of libclang ---------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===--------------------------------------------------------------------===// |
| // |
| // This file implements the 'CXTypes' API hooks in the Clang-C library. |
| // |
| //===--------------------------------------------------------------------===// |
| |
| #include "CIndexer.h" |
| #include "CXCursor.h" |
| #include "CXString.h" |
| #include "CXTranslationUnit.h" |
| #include "CXType.h" |
| #include "clang/AST/Decl.h" |
| #include "clang/AST/DeclObjC.h" |
| #include "clang/AST/DeclTemplate.h" |
| #include "clang/AST/Expr.h" |
| #include "clang/AST/Type.h" |
| #include "clang/Basic/AddressSpaces.h" |
| #include "clang/Frontend/ASTUnit.h" |
| |
| using namespace clang; |
| |
| static CXTypeKind GetBuiltinTypeKind(const BuiltinType *BT) { |
| #define BTCASE(K) case BuiltinType::K: return CXType_##K |
| switch (BT->getKind()) { |
| BTCASE(Void); |
| BTCASE(Bool); |
| BTCASE(Char_U); |
| BTCASE(UChar); |
| BTCASE(Char16); |
| BTCASE(Char32); |
| BTCASE(UShort); |
| BTCASE(UInt); |
| BTCASE(ULong); |
| BTCASE(ULongLong); |
| BTCASE(UInt128); |
| BTCASE(Char_S); |
| BTCASE(SChar); |
| case BuiltinType::WChar_S: return CXType_WChar; |
| case BuiltinType::WChar_U: return CXType_WChar; |
| BTCASE(Short); |
| BTCASE(Int); |
| BTCASE(Long); |
| BTCASE(LongLong); |
| BTCASE(Int128); |
| BTCASE(Half); |
| BTCASE(Float); |
| BTCASE(Double); |
| BTCASE(LongDouble); |
| BTCASE(ShortAccum); |
| BTCASE(Accum); |
| BTCASE(LongAccum); |
| BTCASE(UShortAccum); |
| BTCASE(UAccum); |
| BTCASE(ULongAccum); |
| BTCASE(Float16); |
| BTCASE(Float128); |
| BTCASE(Ibm128); |
| BTCASE(NullPtr); |
| BTCASE(Overload); |
| BTCASE(Dependent); |
| BTCASE(ObjCId); |
| BTCASE(ObjCClass); |
| BTCASE(ObjCSel); |
| #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) BTCASE(Id); |
| #include "clang/Basic/OpenCLImageTypes.def" |
| #undef IMAGE_TYPE |
| #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) BTCASE(Id); |
| #include "clang/Basic/OpenCLExtensionTypes.def" |
| BTCASE(OCLSampler); |
| BTCASE(OCLEvent); |
| BTCASE(OCLQueue); |
| BTCASE(OCLReserveID); |
| default: |
| return CXType_Unexposed; |
| } |
| #undef BTCASE |
| } |
| |
| static CXTypeKind GetTypeKind(QualType T) { |
| const Type *TP = T.getTypePtrOrNull(); |
| if (!TP) |
| return CXType_Invalid; |
| |
| #define TKCASE(K) case Type::K: return CXType_##K |
| switch (TP->getTypeClass()) { |
| case Type::Builtin: |
| return GetBuiltinTypeKind(cast<BuiltinType>(TP)); |
| TKCASE(Complex); |
| TKCASE(Pointer); |
| TKCASE(BlockPointer); |
| TKCASE(LValueReference); |
| TKCASE(RValueReference); |
| TKCASE(Record); |
| TKCASE(Enum); |
| TKCASE(Typedef); |
| TKCASE(ObjCInterface); |
| TKCASE(ObjCObject); |
| TKCASE(ObjCObjectPointer); |
| TKCASE(ObjCTypeParam); |
| TKCASE(FunctionNoProto); |
| TKCASE(FunctionProto); |
| TKCASE(ConstantArray); |
| TKCASE(IncompleteArray); |
| TKCASE(VariableArray); |
| TKCASE(DependentSizedArray); |
| TKCASE(Vector); |
| TKCASE(ExtVector); |
| TKCASE(MemberPointer); |
| TKCASE(Auto); |
| TKCASE(Elaborated); |
| TKCASE(Pipe); |
| TKCASE(Attributed); |
| TKCASE(Atomic); |
| default: |
| return CXType_Unexposed; |
| } |
| #undef TKCASE |
| } |
| |
| |
| CXType cxtype::MakeCXType(QualType T, CXTranslationUnit TU) { |
| CXTypeKind TK = CXType_Invalid; |
| |
| if (TU && !T.isNull()) { |
| // Handle attributed types as the original type |
| if (auto *ATT = T->getAs<AttributedType>()) { |
| if (!(TU->ParsingOptions & CXTranslationUnit_IncludeAttributedTypes)) { |
| // Return the equivalent type which represents the canonically |
| // equivalent type. |
| return MakeCXType(ATT->getEquivalentType(), TU); |
| } |
| } |
| // Handle paren types as the original type |
| if (auto *PTT = T->getAs<ParenType>()) { |
| return MakeCXType(PTT->getInnerType(), TU); |
| } |
| |
| ASTContext &Ctx = cxtu::getASTUnit(TU)->getASTContext(); |
| if (Ctx.getLangOpts().ObjC) { |
| QualType UnqualT = T.getUnqualifiedType(); |
| if (Ctx.isObjCIdType(UnqualT)) |
| TK = CXType_ObjCId; |
| else if (Ctx.isObjCClassType(UnqualT)) |
| TK = CXType_ObjCClass; |
| else if (Ctx.isObjCSelType(UnqualT)) |
| TK = CXType_ObjCSel; |
| } |
| |
| /* Handle decayed types as the original type */ |
| if (const DecayedType *DT = T->getAs<DecayedType>()) { |
| return MakeCXType(DT->getOriginalType(), TU); |
| } |
| } |
| if (TK == CXType_Invalid) |
| TK = GetTypeKind(T); |
| |
| CXType CT = { TK, { TK == CXType_Invalid ? nullptr |
| : T.getAsOpaquePtr(), TU } }; |
| return CT; |
| } |
| |
| using cxtype::MakeCXType; |
| |
| static inline QualType GetQualType(CXType CT) { |
| return QualType::getFromOpaquePtr(CT.data[0]); |
| } |
| |
| static inline CXTranslationUnit GetTU(CXType CT) { |
| return static_cast<CXTranslationUnit>(CT.data[1]); |
| } |
| |
| static Optional<ArrayRef<TemplateArgument>> |
| GetTemplateArguments(QualType Type) { |
| assert(!Type.isNull()); |
| if (const auto *Specialization = Type->getAs<TemplateSpecializationType>()) |
| return Specialization->template_arguments(); |
| |
| if (const auto *RecordDecl = Type->getAsCXXRecordDecl()) { |
| const auto *TemplateDecl = |
| dyn_cast<ClassTemplateSpecializationDecl>(RecordDecl); |
| if (TemplateDecl) |
| return TemplateDecl->getTemplateArgs().asArray(); |
| } |
| |
| return None; |
| } |
| |
| static Optional<QualType> TemplateArgumentToQualType(const TemplateArgument &A) { |
| if (A.getKind() == TemplateArgument::Type) |
| return A.getAsType(); |
| return None; |
| } |
| |
| static Optional<QualType> |
| FindTemplateArgumentTypeAt(ArrayRef<TemplateArgument> TA, unsigned index) { |
| unsigned current = 0; |
| for (const auto &A : TA) { |
| if (A.getKind() == TemplateArgument::Pack) { |
| if (index < current + A.pack_size()) |
| return TemplateArgumentToQualType(A.getPackAsArray()[index - current]); |
| current += A.pack_size(); |
| continue; |
| } |
| if (current == index) |
| return TemplateArgumentToQualType(A); |
| current++; |
| } |
| return None; |
| } |
| |
| CXType clang_getCursorType(CXCursor C) { |
| using namespace cxcursor; |
| |
| CXTranslationUnit TU = cxcursor::getCursorTU(C); |
| if (!TU) |
| return MakeCXType(QualType(), TU); |
| |
| ASTContext &Context = cxtu::getASTUnit(TU)->getASTContext(); |
| if (clang_isExpression(C.kind)) { |
| QualType T = cxcursor::getCursorExpr(C)->getType(); |
| return MakeCXType(T, TU); |
| } |
| |
| if (clang_isDeclaration(C.kind)) { |
| const Decl *D = cxcursor::getCursorDecl(C); |
| if (!D) |
| return MakeCXType(QualType(), TU); |
| |
| if (const TypeDecl *TD = dyn_cast<TypeDecl>(D)) |
| return MakeCXType(Context.getTypeDeclType(TD), TU); |
| if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) |
| return MakeCXType(Context.getObjCInterfaceType(ID), TU); |
| if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) |
| return MakeCXType(DD->getType(), TU); |
| if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) |
| return MakeCXType(VD->getType(), TU); |
| if (const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) |
| return MakeCXType(PD->getType(), TU); |
| if (const FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D)) |
| return MakeCXType(FTD->getTemplatedDecl()->getType(), TU); |
| return MakeCXType(QualType(), TU); |
| } |
| |
| if (clang_isReference(C.kind)) { |
| switch (C.kind) { |
| case CXCursor_ObjCSuperClassRef: { |
| QualType T |
| = Context.getObjCInterfaceType(getCursorObjCSuperClassRef(C).first); |
| return MakeCXType(T, TU); |
| } |
| |
| case CXCursor_ObjCClassRef: { |
| QualType T = Context.getObjCInterfaceType(getCursorObjCClassRef(C).first); |
| return MakeCXType(T, TU); |
| } |
| |
| case CXCursor_TypeRef: { |
| QualType T = Context.getTypeDeclType(getCursorTypeRef(C).first); |
| return MakeCXType(T, TU); |
| |
| } |
| |
| case CXCursor_CXXBaseSpecifier: |
| return cxtype::MakeCXType(getCursorCXXBaseSpecifier(C)->getType(), TU); |
| |
| case CXCursor_MemberRef: |
| return cxtype::MakeCXType(getCursorMemberRef(C).first->getType(), TU); |
| |
| case CXCursor_VariableRef: |
| return cxtype::MakeCXType(getCursorVariableRef(C).first->getType(), TU); |
| |
| case CXCursor_ObjCProtocolRef: |
| case CXCursor_TemplateRef: |
| case CXCursor_NamespaceRef: |
| case CXCursor_OverloadedDeclRef: |
| default: |
| break; |
| } |
| |
| return MakeCXType(QualType(), TU); |
| } |
| |
| return MakeCXType(QualType(), TU); |
| } |
| |
| CXString clang_getTypeSpelling(CXType CT) { |
| QualType T = GetQualType(CT); |
| if (T.isNull()) |
| return cxstring::createEmpty(); |
| |
| CXTranslationUnit TU = GetTU(CT); |
| SmallString<64> Str; |
| llvm::raw_svector_ostream OS(Str); |
| PrintingPolicy PP(cxtu::getASTUnit(TU)->getASTContext().getLangOpts()); |
| |
| T.print(OS, PP); |
| |
| return cxstring::createDup(OS.str()); |
| } |
| |
| CXType clang_getTypedefDeclUnderlyingType(CXCursor C) { |
| using namespace cxcursor; |
| CXTranslationUnit TU = cxcursor::getCursorTU(C); |
| |
| if (clang_isDeclaration(C.kind)) { |
| const Decl *D = cxcursor::getCursorDecl(C); |
| |
| if (const TypedefNameDecl *TD = dyn_cast_or_null<TypedefNameDecl>(D)) { |
| QualType T = TD->getUnderlyingType(); |
| return MakeCXType(T, TU); |
| } |
| |
| return MakeCXType(QualType(), TU); |
| } |
| |
| return MakeCXType(QualType(), TU); |
| } |
| |
| CXType clang_getEnumDeclIntegerType(CXCursor C) { |
| using namespace cxcursor; |
| CXTranslationUnit TU = cxcursor::getCursorTU(C); |
| |
| if (clang_isDeclaration(C.kind)) { |
| const Decl *D = cxcursor::getCursorDecl(C); |
| |
| if (const EnumDecl *TD = dyn_cast_or_null<EnumDecl>(D)) { |
| QualType T = TD->getIntegerType(); |
| return MakeCXType(T, TU); |
| } |
| |
| return MakeCXType(QualType(), TU); |
| } |
| |
| return MakeCXType(QualType(), TU); |
| } |
| |
| long long clang_getEnumConstantDeclValue(CXCursor C) { |
| using namespace cxcursor; |
| |
| if (clang_isDeclaration(C.kind)) { |
| const Decl *D = cxcursor::getCursorDecl(C); |
| |
| if (const EnumConstantDecl *TD = dyn_cast_or_null<EnumConstantDecl>(D)) { |
| return TD->getInitVal().getSExtValue(); |
| } |
| |
| return LLONG_MIN; |
| } |
| |
| return LLONG_MIN; |
| } |
| |
| unsigned long long clang_getEnumConstantDeclUnsignedValue(CXCursor C) { |
| using namespace cxcursor; |
| |
| if (clang_isDeclaration(C.kind)) { |
| const Decl *D = cxcursor::getCursorDecl(C); |
| |
| if (const EnumConstantDecl *TD = dyn_cast_or_null<EnumConstantDecl>(D)) { |
| return TD->getInitVal().getZExtValue(); |
| } |
| |
| return ULLONG_MAX; |
| } |
| |
| return ULLONG_MAX; |
| } |
| |
| int clang_getFieldDeclBitWidth(CXCursor C) { |
| using namespace cxcursor; |
| |
| if (clang_isDeclaration(C.kind)) { |
| const Decl *D = getCursorDecl(C); |
| |
| if (const FieldDecl *FD = dyn_cast_or_null<FieldDecl>(D)) { |
| if (FD->isBitField()) |
| return FD->getBitWidthValue(getCursorContext(C)); |
| } |
| } |
| |
| return -1; |
| } |
| |
| CXType clang_getCanonicalType(CXType CT) { |
| if (CT.kind == CXType_Invalid) |
| return CT; |
| |
| QualType T = GetQualType(CT); |
| CXTranslationUnit TU = GetTU(CT); |
| |
| if (T.isNull()) |
| return MakeCXType(QualType(), GetTU(CT)); |
| |
| return MakeCXType(cxtu::getASTUnit(TU)->getASTContext() |
| .getCanonicalType(T), |
| TU); |
| } |
| |
| unsigned clang_isConstQualifiedType(CXType CT) { |
| QualType T = GetQualType(CT); |
| return T.isLocalConstQualified(); |
| } |
| |
| unsigned clang_isVolatileQualifiedType(CXType CT) { |
| QualType T = GetQualType(CT); |
| return T.isLocalVolatileQualified(); |
| } |
| |
| unsigned clang_isRestrictQualifiedType(CXType CT) { |
| QualType T = GetQualType(CT); |
| return T.isLocalRestrictQualified(); |
| } |
| |
| unsigned clang_getAddressSpace(CXType CT) { |
| QualType T = GetQualType(CT); |
| |
| // For non language-specific address space, use separate helper function. |
| if (T.getAddressSpace() >= LangAS::FirstTargetAddressSpace) { |
| return T.getQualifiers().getAddressSpaceAttributePrintValue(); |
| } |
| // FIXME: this function returns either a LangAS or a target AS |
| // Those values can overlap which makes this function rather unpredictable |
| // for any caller |
| return (unsigned)T.getAddressSpace(); |
| } |
| |
| CXString clang_getTypedefName(CXType CT) { |
| QualType T = GetQualType(CT); |
| const TypedefType *TT = T->getAs<TypedefType>(); |
| if (TT) { |
| TypedefNameDecl *TD = TT->getDecl(); |
| if (TD) |
| return cxstring::createDup(TD->getNameAsString().c_str()); |
| } |
| return cxstring::createEmpty(); |
| } |
| |
| CXType clang_getPointeeType(CXType CT) { |
| QualType T = GetQualType(CT); |
| const Type *TP = T.getTypePtrOrNull(); |
| |
| if (!TP) |
| return MakeCXType(QualType(), GetTU(CT)); |
| |
| try_again: |
| switch (TP->getTypeClass()) { |
| case Type::Pointer: |
| T = cast<PointerType>(TP)->getPointeeType(); |
| break; |
| case Type::BlockPointer: |
| T = cast<BlockPointerType>(TP)->getPointeeType(); |
| break; |
| case Type::LValueReference: |
| case Type::RValueReference: |
| T = cast<ReferenceType>(TP)->getPointeeType(); |
| break; |
| case Type::ObjCObjectPointer: |
| T = cast<ObjCObjectPointerType>(TP)->getPointeeType(); |
| break; |
| case Type::MemberPointer: |
| T = cast<MemberPointerType>(TP)->getPointeeType(); |
| break; |
| case Type::Auto: |
| case Type::DeducedTemplateSpecialization: |
| TP = cast<DeducedType>(TP)->getDeducedType().getTypePtrOrNull(); |
| if (TP) |
| goto try_again; |
| break; |
| default: |
| T = QualType(); |
| break; |
| } |
| return MakeCXType(T, GetTU(CT)); |
| } |
| |
| CXCursor clang_getTypeDeclaration(CXType CT) { |
| if (CT.kind == CXType_Invalid) |
| return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound); |
| |
| QualType T = GetQualType(CT); |
| const Type *TP = T.getTypePtrOrNull(); |
| |
| if (!TP) |
| return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound); |
| |
| Decl *D = nullptr; |
| |
| try_again: |
| switch (TP->getTypeClass()) { |
| case Type::Typedef: |
| D = cast<TypedefType>(TP)->getDecl(); |
| break; |
| case Type::ObjCObject: |
| D = cast<ObjCObjectType>(TP)->getInterface(); |
| break; |
| case Type::ObjCInterface: |
| D = cast<ObjCInterfaceType>(TP)->getDecl(); |
| break; |
| case Type::Record: |
| case Type::Enum: |
| D = cast<TagType>(TP)->getDecl(); |
| break; |
| case Type::TemplateSpecialization: |
| if (const RecordType *Record = TP->getAs<RecordType>()) |
| D = Record->getDecl(); |
| else |
| D = cast<TemplateSpecializationType>(TP)->getTemplateName() |
| .getAsTemplateDecl(); |
| break; |
| |
| case Type::Auto: |
| case Type::DeducedTemplateSpecialization: |
| TP = cast<DeducedType>(TP)->getDeducedType().getTypePtrOrNull(); |
| if (TP) |
| goto try_again; |
| break; |
| |
| case Type::InjectedClassName: |
| D = cast<InjectedClassNameType>(TP)->getDecl(); |
| break; |
| |
| // FIXME: Template type parameters! |
| |
| case Type::Elaborated: |
| TP = cast<ElaboratedType>(TP)->getNamedType().getTypePtrOrNull(); |
| goto try_again; |
| |
| default: |
| break; |
| } |
| |
| if (!D) |
| return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound); |
| |
| return cxcursor::MakeCXCursor(D, GetTU(CT)); |
| } |
| |
| CXString clang_getTypeKindSpelling(enum CXTypeKind K) { |
| const char *s = nullptr; |
| #define TKIND(X) case CXType_##X: s = "" #X ""; break |
| switch (K) { |
| TKIND(Invalid); |
| TKIND(Unexposed); |
| TKIND(Void); |
| TKIND(Bool); |
| TKIND(Char_U); |
| TKIND(UChar); |
| TKIND(Char16); |
| TKIND(Char32); |
| TKIND(UShort); |
| TKIND(UInt); |
| TKIND(ULong); |
| TKIND(ULongLong); |
| TKIND(UInt128); |
| TKIND(Char_S); |
| TKIND(SChar); |
| case CXType_WChar: s = "WChar"; break; |
| TKIND(Short); |
| TKIND(Int); |
| TKIND(Long); |
| TKIND(LongLong); |
| TKIND(Int128); |
| TKIND(Half); |
| TKIND(Float); |
| TKIND(Double); |
| TKIND(LongDouble); |
| TKIND(ShortAccum); |
| TKIND(Accum); |
| TKIND(LongAccum); |
| TKIND(UShortAccum); |
| TKIND(UAccum); |
| TKIND(ULongAccum); |
| TKIND(Float16); |
| TKIND(Float128); |
| TKIND(Ibm128); |
| TKIND(NullPtr); |
| TKIND(Overload); |
| TKIND(Dependent); |
| TKIND(ObjCId); |
| TKIND(ObjCClass); |
| TKIND(ObjCSel); |
| TKIND(Complex); |
| TKIND(Pointer); |
| TKIND(BlockPointer); |
| TKIND(LValueReference); |
| TKIND(RValueReference); |
| TKIND(Record); |
| TKIND(Enum); |
| TKIND(Typedef); |
| TKIND(ObjCInterface); |
| TKIND(ObjCObject); |
| TKIND(ObjCObjectPointer); |
| TKIND(ObjCTypeParam); |
| TKIND(FunctionNoProto); |
| TKIND(FunctionProto); |
| TKIND(ConstantArray); |
| TKIND(IncompleteArray); |
| TKIND(VariableArray); |
| TKIND(DependentSizedArray); |
| TKIND(Vector); |
| TKIND(ExtVector); |
| TKIND(MemberPointer); |
| TKIND(Auto); |
| TKIND(Elaborated); |
| TKIND(Pipe); |
| TKIND(Attributed); |
| TKIND(BFloat16); |
| #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) TKIND(Id); |
| #include "clang/Basic/OpenCLImageTypes.def" |
| #undef IMAGE_TYPE |
| #define EXT_OPAQUE_TYPE(ExtTYpe, Id, Ext) TKIND(Id); |
| #include "clang/Basic/OpenCLExtensionTypes.def" |
| TKIND(OCLSampler); |
| TKIND(OCLEvent); |
| TKIND(OCLQueue); |
| TKIND(OCLReserveID); |
| TKIND(Atomic); |
| } |
| #undef TKIND |
| return cxstring::createRef(s); |
| } |
| |
| unsigned clang_equalTypes(CXType A, CXType B) { |
| return A.data[0] == B.data[0] && A.data[1] == B.data[1]; |
| } |
| |
| unsigned clang_isFunctionTypeVariadic(CXType X) { |
| QualType T = GetQualType(X); |
| if (T.isNull()) |
| return 0; |
| |
| if (const FunctionProtoType *FD = T->getAs<FunctionProtoType>()) |
| return (unsigned)FD->isVariadic(); |
| |
| if (T->getAs<FunctionNoProtoType>()) |
| return 1; |
| |
| return 0; |
| } |
| |
| CXCallingConv clang_getFunctionTypeCallingConv(CXType X) { |
| QualType T = GetQualType(X); |
| if (T.isNull()) |
| return CXCallingConv_Invalid; |
| |
| if (const FunctionType *FD = T->getAs<FunctionType>()) { |
| #define TCALLINGCONV(X) case CC_##X: return CXCallingConv_##X |
| switch (FD->getCallConv()) { |
| TCALLINGCONV(C); |
| TCALLINGCONV(X86StdCall); |
| TCALLINGCONV(X86FastCall); |
| TCALLINGCONV(X86ThisCall); |
| TCALLINGCONV(X86Pascal); |
| TCALLINGCONV(X86RegCall); |
| TCALLINGCONV(X86VectorCall); |
| TCALLINGCONV(AArch64VectorCall); |
| TCALLINGCONV(Win64); |
| TCALLINGCONV(X86_64SysV); |
| TCALLINGCONV(AAPCS); |
| TCALLINGCONV(AAPCS_VFP); |
| TCALLINGCONV(IntelOclBicc); |
| TCALLINGCONV(Swift); |
| TCALLINGCONV(SwiftAsync); |
| TCALLINGCONV(PreserveMost); |
| TCALLINGCONV(PreserveAll); |
| case CC_SpirFunction: return CXCallingConv_Unexposed; |
| case CC_OpenCLKernel: return CXCallingConv_Unexposed; |
| break; |
| } |
| #undef TCALLINGCONV |
| } |
| |
| return CXCallingConv_Invalid; |
| } |
| |
| int clang_getNumArgTypes(CXType X) { |
| QualType T = GetQualType(X); |
| if (T.isNull()) |
| return -1; |
| |
| if (const FunctionProtoType *FD = T->getAs<FunctionProtoType>()) { |
| return FD->getNumParams(); |
| } |
| |
| if (T->getAs<FunctionNoProtoType>()) { |
| return 0; |
| } |
| |
| return -1; |
| } |
| |
| CXType clang_getArgType(CXType X, unsigned i) { |
| QualType T = GetQualType(X); |
| if (T.isNull()) |
| return MakeCXType(QualType(), GetTU(X)); |
| |
| if (const FunctionProtoType *FD = T->getAs<FunctionProtoType>()) { |
| unsigned numParams = FD->getNumParams(); |
| if (i >= numParams) |
| return MakeCXType(QualType(), GetTU(X)); |
| |
| return MakeCXType(FD->getParamType(i), GetTU(X)); |
| } |
| |
| return MakeCXType(QualType(), GetTU(X)); |
| } |
| |
| CXType clang_getResultType(CXType X) { |
| QualType T = GetQualType(X); |
| if (T.isNull()) |
| return MakeCXType(QualType(), GetTU(X)); |
| |
| if (const FunctionType *FD = T->getAs<FunctionType>()) |
| return MakeCXType(FD->getReturnType(), GetTU(X)); |
| |
| return MakeCXType(QualType(), GetTU(X)); |
| } |
| |
| CXType clang_getCursorResultType(CXCursor C) { |
| if (clang_isDeclaration(C.kind)) { |
| const Decl *D = cxcursor::getCursorDecl(C); |
| if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D)) |
| return MakeCXType(MD->getReturnType(), cxcursor::getCursorTU(C)); |
| |
| return clang_getResultType(clang_getCursorType(C)); |
| } |
| |
| return MakeCXType(QualType(), cxcursor::getCursorTU(C)); |
| } |
| |
| // FIXME: We should expose the canThrow(...) result instead of the EST. |
| static CXCursor_ExceptionSpecificationKind |
| getExternalExceptionSpecificationKind(ExceptionSpecificationType EST) { |
| switch (EST) { |
| case EST_None: |
| return CXCursor_ExceptionSpecificationKind_None; |
| case EST_DynamicNone: |
| return CXCursor_ExceptionSpecificationKind_DynamicNone; |
| case EST_Dynamic: |
| return CXCursor_ExceptionSpecificationKind_Dynamic; |
| case EST_MSAny: |
| return CXCursor_ExceptionSpecificationKind_MSAny; |
| case EST_BasicNoexcept: |
| return CXCursor_ExceptionSpecificationKind_BasicNoexcept; |
| case EST_NoThrow: |
| return CXCursor_ExceptionSpecificationKind_NoThrow; |
| case EST_NoexceptFalse: |
| case EST_NoexceptTrue: |
| case EST_DependentNoexcept: |
| return CXCursor_ExceptionSpecificationKind_ComputedNoexcept; |
| case EST_Unevaluated: |
| return CXCursor_ExceptionSpecificationKind_Unevaluated; |
| case EST_Uninstantiated: |
| return CXCursor_ExceptionSpecificationKind_Uninstantiated; |
| case EST_Unparsed: |
| return CXCursor_ExceptionSpecificationKind_Unparsed; |
| } |
| llvm_unreachable("invalid EST value"); |
| } |
| |
| int clang_getExceptionSpecificationType(CXType X) { |
| QualType T = GetQualType(X); |
| if (T.isNull()) |
| return -1; |
| |
| if (const auto *FD = T->getAs<FunctionProtoType>()) |
| return getExternalExceptionSpecificationKind(FD->getExceptionSpecType()); |
| |
| return -1; |
| } |
| |
| int clang_getCursorExceptionSpecificationType(CXCursor C) { |
| if (clang_isDeclaration(C.kind)) |
| return clang_getExceptionSpecificationType(clang_getCursorType(C)); |
| |
| return -1; |
| } |
| |
| unsigned clang_isPODType(CXType X) { |
| QualType T = GetQualType(X); |
| if (T.isNull()) |
| return 0; |
| |
| CXTranslationUnit TU = GetTU(X); |
| |
| return T.isPODType(cxtu::getASTUnit(TU)->getASTContext()) ? 1 : 0; |
| } |
| |
| CXType clang_getElementType(CXType CT) { |
| QualType ET = QualType(); |
| QualType T = GetQualType(CT); |
| const Type *TP = T.getTypePtrOrNull(); |
| |
| if (TP) { |
| switch (TP->getTypeClass()) { |
| case Type::ConstantArray: |
| ET = cast<ConstantArrayType> (TP)->getElementType(); |
| break; |
| case Type::IncompleteArray: |
| ET = cast<IncompleteArrayType> (TP)->getElementType(); |
| break; |
| case Type::VariableArray: |
| ET = cast<VariableArrayType> (TP)->getElementType(); |
| break; |
| case Type::DependentSizedArray: |
| ET = cast<DependentSizedArrayType> (TP)->getElementType(); |
| break; |
| case Type::Vector: |
| ET = cast<VectorType> (TP)->getElementType(); |
| break; |
| case Type::ExtVector: |
| ET = cast<ExtVectorType>(TP)->getElementType(); |
| break; |
| case Type::Complex: |
| ET = cast<ComplexType> (TP)->getElementType(); |
| break; |
| default: |
| break; |
| } |
| } |
| return MakeCXType(ET, GetTU(CT)); |
| } |
| |
| long long clang_getNumElements(CXType CT) { |
| long long result = -1; |
| QualType T = GetQualType(CT); |
| const Type *TP = T.getTypePtrOrNull(); |
| |
| if (TP) { |
| switch (TP->getTypeClass()) { |
| case Type::ConstantArray: |
| result = cast<ConstantArrayType> (TP)->getSize().getSExtValue(); |
| break; |
| case Type::Vector: |
| result = cast<VectorType> (TP)->getNumElements(); |
| break; |
| case Type::ExtVector: |
| result = cast<ExtVectorType>(TP)->getNumElements(); |
| break; |
| default: |
| break; |
| } |
| } |
| return result; |
| } |
| |
| CXType clang_getArrayElementType(CXType CT) { |
| QualType ET = QualType(); |
| QualType T = GetQualType(CT); |
| const Type *TP = T.getTypePtrOrNull(); |
| |
| if (TP) { |
| switch (TP->getTypeClass()) { |
| case Type::ConstantArray: |
| ET = cast<ConstantArrayType> (TP)->getElementType(); |
| break; |
| case Type::IncompleteArray: |
| ET = cast<IncompleteArrayType> (TP)->getElementType(); |
| break; |
| case Type::VariableArray: |
| ET = cast<VariableArrayType> (TP)->getElementType(); |
| break; |
| case Type::DependentSizedArray: |
| ET = cast<DependentSizedArrayType> (TP)->getElementType(); |
| break; |
| default: |
| break; |
| } |
| } |
| return MakeCXType(ET, GetTU(CT)); |
| } |
| |
| long long clang_getArraySize(CXType CT) { |
| long long result = -1; |
| QualType T = GetQualType(CT); |
| const Type *TP = T.getTypePtrOrNull(); |
| |
| if (TP) { |
| switch (TP->getTypeClass()) { |
| case Type::ConstantArray: |
| result = cast<ConstantArrayType> (TP)->getSize().getSExtValue(); |
| break; |
| default: |
| break; |
| } |
| } |
| return result; |
| } |
| |
| static bool isIncompleteTypeWithAlignment(QualType QT) { |
| return QT->isIncompleteArrayType() || !QT->isIncompleteType(); |
| } |
| |
| long long clang_Type_getAlignOf(CXType T) { |
| if (T.kind == CXType_Invalid) |
| return CXTypeLayoutError_Invalid; |
| ASTContext &Ctx = cxtu::getASTUnit(GetTU(T))->getASTContext(); |
| QualType QT = GetQualType(T); |
| // [expr.alignof] p1: return size_t value for complete object type, reference |
| // or array. |
| // [expr.alignof] p3: if reference type, return size of referenced type |
| if (QT->isReferenceType()) |
| QT = QT.getNonReferenceType(); |
| if (!isIncompleteTypeWithAlignment(QT)) |
| return CXTypeLayoutError_Incomplete; |
| if (QT->isDependentType()) |
| return CXTypeLayoutError_Dependent; |
| if (const auto *Deduced = dyn_cast<DeducedType>(QT)) |
| if (Deduced->getDeducedType().isNull()) |
| return CXTypeLayoutError_Undeduced; |
| // Exceptions by GCC extension - see ASTContext.cpp:1313 getTypeInfoImpl |
| // if (QT->isFunctionType()) return 4; // Bug #15511 - should be 1 |
| // if (QT->isVoidType()) return 1; |
| return Ctx.getTypeAlignInChars(QT).getQuantity(); |
| } |
| |
| CXType clang_Type_getClassType(CXType CT) { |
| QualType ET = QualType(); |
| QualType T = GetQualType(CT); |
| const Type *TP = T.getTypePtrOrNull(); |
| |
| if (TP && TP->getTypeClass() == Type::MemberPointer) { |
| ET = QualType(cast<MemberPointerType> (TP)->getClass(), 0); |
| } |
| return MakeCXType(ET, GetTU(CT)); |
| } |
| |
| long long clang_Type_getSizeOf(CXType T) { |
| if (T.kind == CXType_Invalid) |
| return CXTypeLayoutError_Invalid; |
| ASTContext &Ctx = cxtu::getASTUnit(GetTU(T))->getASTContext(); |
| QualType QT = GetQualType(T); |
| // [expr.sizeof] p2: if reference type, return size of referenced type |
| if (QT->isReferenceType()) |
| QT = QT.getNonReferenceType(); |
| // [expr.sizeof] p1: return -1 on: func, incomplete, bitfield, incomplete |
| // enumeration |
| // Note: We get the cxtype, not the cxcursor, so we can't call |
| // FieldDecl->isBitField() |
| // [expr.sizeof] p3: pointer ok, function not ok. |
| // [gcc extension] lib/AST/ExprConstant.cpp:1372 HandleSizeof : vla == error |
| if (QT->isIncompleteType()) |
| return CXTypeLayoutError_Incomplete; |
| if (QT->isDependentType()) |
| return CXTypeLayoutError_Dependent; |
| if (!QT->isConstantSizeType()) |
| return CXTypeLayoutError_NotConstantSize; |
| if (const auto *Deduced = dyn_cast<DeducedType>(QT)) |
| if (Deduced->getDeducedType().isNull()) |
| return CXTypeLayoutError_Undeduced; |
| // [gcc extension] lib/AST/ExprConstant.cpp:1372 |
| // HandleSizeof : {voidtype,functype} == 1 |
| // not handled by ASTContext.cpp:1313 getTypeInfoImpl |
| if (QT->isVoidType() || QT->isFunctionType()) |
| return 1; |
| return Ctx.getTypeSizeInChars(QT).getQuantity(); |
| } |
| |
| static bool isTypeIncompleteForLayout(QualType QT) { |
| return QT->isIncompleteType() && !QT->isIncompleteArrayType(); |
| } |
| |
| static long long visitRecordForValidation(const RecordDecl *RD) { |
| for (const auto *I : RD->fields()){ |
| QualType FQT = I->getType(); |
| if (isTypeIncompleteForLayout(FQT)) |
| return CXTypeLayoutError_Incomplete; |
| if (FQT->isDependentType()) |
| return CXTypeLayoutError_Dependent; |
| // recurse |
| if (const RecordType *ChildType = I->getType()->getAs<RecordType>()) { |
| if (const RecordDecl *Child = ChildType->getDecl()) { |
| long long ret = visitRecordForValidation(Child); |
| if (ret < 0) |
| return ret; |
| } |
| } |
| // else try next field |
| } |
| return 0; |
| } |
| |
| static long long validateFieldParentType(CXCursor PC, CXType PT){ |
| if (clang_isInvalid(PC.kind)) |
| return CXTypeLayoutError_Invalid; |
| const RecordDecl *RD = |
| dyn_cast_or_null<RecordDecl>(cxcursor::getCursorDecl(PC)); |
| // validate parent declaration |
| if (!RD || RD->isInvalidDecl()) |
| return CXTypeLayoutError_Invalid; |
| RD = RD->getDefinition(); |
| if (!RD) |
| return CXTypeLayoutError_Incomplete; |
| if (RD->isInvalidDecl()) |
| return CXTypeLayoutError_Invalid; |
| // validate parent type |
| QualType RT = GetQualType(PT); |
| if (RT->isIncompleteType()) |
| return CXTypeLayoutError_Incomplete; |
| if (RT->isDependentType()) |
| return CXTypeLayoutError_Dependent; |
| // We recurse into all record fields to detect incomplete and dependent types. |
| long long Error = visitRecordForValidation(RD); |
| if (Error < 0) |
| return Error; |
| return 0; |
| } |
| |
| long long clang_Type_getOffsetOf(CXType PT, const char *S) { |
| // check that PT is not incomplete/dependent |
| CXCursor PC = clang_getTypeDeclaration(PT); |
| long long Error = validateFieldParentType(PC,PT); |
| if (Error < 0) |
| return Error; |
| if (!S) |
| return CXTypeLayoutError_InvalidFieldName; |
| // lookup field |
| ASTContext &Ctx = cxtu::getASTUnit(GetTU(PT))->getASTContext(); |
| IdentifierInfo *II = &Ctx.Idents.get(S); |
| DeclarationName FieldName(II); |
| const RecordDecl *RD = |
| dyn_cast_or_null<RecordDecl>(cxcursor::getCursorDecl(PC)); |
| // verified in validateFieldParentType |
| RD = RD->getDefinition(); |
| RecordDecl::lookup_result Res = RD->lookup(FieldName); |
| // If a field of the parent record is incomplete, lookup will fail. |
| // and we would return InvalidFieldName instead of Incomplete. |
| // But this erroneous results does protects again a hidden assertion failure |
| // in the RecordLayoutBuilder |
| if (!Res.isSingleResult()) |
| return CXTypeLayoutError_InvalidFieldName; |
| if (const FieldDecl *FD = dyn_cast<FieldDecl>(Res.front())) |
| return Ctx.getFieldOffset(FD); |
| if (const IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(Res.front())) |
| return Ctx.getFieldOffset(IFD); |
| // we don't want any other Decl Type. |
| return CXTypeLayoutError_InvalidFieldName; |
| } |
| |
| CXType clang_Type_getModifiedType(CXType CT) { |
| QualType T = GetQualType(CT); |
| if (T.isNull()) |
| return MakeCXType(QualType(), GetTU(CT)); |
| |
| if (auto *ATT = T->getAs<AttributedType>()) |
| return MakeCXType(ATT->getModifiedType(), GetTU(CT)); |
| |
| return MakeCXType(QualType(), GetTU(CT)); |
| } |
| |
| long long clang_Cursor_getOffsetOfField(CXCursor C) { |
| if (clang_isDeclaration(C.kind)) { |
| // we need to validate the parent type |
| CXCursor PC = clang_getCursorSemanticParent(C); |
| CXType PT = clang_getCursorType(PC); |
| long long Error = validateFieldParentType(PC,PT); |
| if (Error < 0) |
| return Error; |
| // proceed with the offset calculation |
| const Decl *D = cxcursor::getCursorDecl(C); |
| ASTContext &Ctx = cxcursor::getCursorContext(C); |
| if (const FieldDecl *FD = dyn_cast_or_null<FieldDecl>(D)) |
| return Ctx.getFieldOffset(FD); |
| if (const IndirectFieldDecl *IFD = dyn_cast_or_null<IndirectFieldDecl>(D)) |
| return Ctx.getFieldOffset(IFD); |
| } |
| return -1; |
| } |
| |
| enum CXRefQualifierKind clang_Type_getCXXRefQualifier(CXType T) { |
| QualType QT = GetQualType(T); |
| if (QT.isNull()) |
| return CXRefQualifier_None; |
| const FunctionProtoType *FD = QT->getAs<FunctionProtoType>(); |
| if (!FD) |
| return CXRefQualifier_None; |
| switch (FD->getRefQualifier()) { |
| case RQ_None: |
| return CXRefQualifier_None; |
| case RQ_LValue: |
| return CXRefQualifier_LValue; |
| case RQ_RValue: |
| return CXRefQualifier_RValue; |
| } |
| return CXRefQualifier_None; |
| } |
| |
| unsigned clang_Cursor_isBitField(CXCursor C) { |
| if (!clang_isDeclaration(C.kind)) |
| return 0; |
| const FieldDecl *FD = dyn_cast_or_null<FieldDecl>(cxcursor::getCursorDecl(C)); |
| if (!FD) |
| return 0; |
| return FD->isBitField(); |
| } |
| |
| CXString clang_getDeclObjCTypeEncoding(CXCursor C) { |
| if (!clang_isDeclaration(C.kind)) |
| return cxstring::createEmpty(); |
| |
| const Decl *D = cxcursor::getCursorDecl(C); |
| ASTContext &Ctx = cxcursor::getCursorContext(C); |
| std::string encoding; |
| |
| if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) { |
| encoding = Ctx.getObjCEncodingForMethodDecl(OMD); |
| } else if (const ObjCPropertyDecl *OPD = dyn_cast<ObjCPropertyDecl>(D)) |
| encoding = Ctx.getObjCEncodingForPropertyDecl(OPD, nullptr); |
| else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) |
| encoding = Ctx.getObjCEncodingForFunctionDecl(FD); |
| else { |
| QualType Ty; |
| if (const TypeDecl *TD = dyn_cast<TypeDecl>(D)) |
| Ty = Ctx.getTypeDeclType(TD); |
| if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) |
| Ty = VD->getType(); |
| else return cxstring::createRef("?"); |
| Ctx.getObjCEncodingForType(Ty, encoding); |
| } |
| |
| return cxstring::createDup(encoding); |
| } |
| |
| static unsigned GetTemplateArgumentArraySize(ArrayRef<TemplateArgument> TA) { |
| unsigned size = TA.size(); |
| for (const auto &Arg : TA) |
| if (Arg.getKind() == TemplateArgument::Pack) |
| size += Arg.pack_size() - 1; |
| return size; |
| } |
| |
| int clang_Type_getNumTemplateArguments(CXType CT) { |
| QualType T = GetQualType(CT); |
| if (T.isNull()) |
| return -1; |
| |
| auto TA = GetTemplateArguments(T); |
| if (!TA) |
| return -1; |
| |
| return GetTemplateArgumentArraySize(TA.getValue()); |
| } |
| |
| CXType clang_Type_getTemplateArgumentAsType(CXType CT, unsigned index) { |
| QualType T = GetQualType(CT); |
| if (T.isNull()) |
| return MakeCXType(QualType(), GetTU(CT)); |
| |
| auto TA = GetTemplateArguments(T); |
| if (!TA) |
| return MakeCXType(QualType(), GetTU(CT)); |
| |
| Optional<QualType> QT = FindTemplateArgumentTypeAt(TA.getValue(), index); |
| return MakeCXType(QT.getValueOr(QualType()), GetTU(CT)); |
| } |
| |
| CXType clang_Type_getObjCObjectBaseType(CXType CT) { |
| QualType T = GetQualType(CT); |
| if (T.isNull()) |
| return MakeCXType(QualType(), GetTU(CT)); |
| |
| const ObjCObjectType *OT = dyn_cast<ObjCObjectType>(T); |
| if (!OT) |
| return MakeCXType(QualType(), GetTU(CT)); |
| |
| return MakeCXType(OT->getBaseType(), GetTU(CT)); |
| } |
| |
| unsigned clang_Type_getNumObjCProtocolRefs(CXType CT) { |
| QualType T = GetQualType(CT); |
| if (T.isNull()) |
| return 0; |
| |
| const ObjCObjectType *OT = dyn_cast<ObjCObjectType>(T); |
| if (!OT) |
| return 0; |
| |
| return OT->getNumProtocols(); |
| } |
| |
| CXCursor clang_Type_getObjCProtocolDecl(CXType CT, unsigned i) { |
| QualType T = GetQualType(CT); |
| if (T.isNull()) |
| return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound); |
| |
| const ObjCObjectType *OT = dyn_cast<ObjCObjectType>(T); |
| if (!OT) |
| return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound); |
| |
| const ObjCProtocolDecl *PD = OT->getProtocol(i); |
| if (!PD) |
| return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound); |
| |
| return cxcursor::MakeCXCursor(PD, GetTU(CT)); |
| } |
| |
| unsigned clang_Type_getNumObjCTypeArgs(CXType CT) { |
| QualType T = GetQualType(CT); |
| if (T.isNull()) |
| return 0; |
| |
| const ObjCObjectType *OT = dyn_cast<ObjCObjectType>(T); |
| if (!OT) |
| return 0; |
| |
| return OT->getTypeArgs().size(); |
| } |
| |
| CXType clang_Type_getObjCTypeArg(CXType CT, unsigned i) { |
| QualType T = GetQualType(CT); |
| if (T.isNull()) |
| return MakeCXType(QualType(), GetTU(CT)); |
| |
| const ObjCObjectType *OT = dyn_cast<ObjCObjectType>(T); |
| if (!OT) |
| return MakeCXType(QualType(), GetTU(CT)); |
| |
| const ArrayRef<QualType> TA = OT->getTypeArgs(); |
| if ((size_t)i >= TA.size()) |
| return MakeCXType(QualType(), GetTU(CT)); |
| |
| return MakeCXType(TA[i], GetTU(CT)); |
| } |
| |
| unsigned clang_Type_visitFields(CXType PT, |
| CXFieldVisitor visitor, |
| CXClientData client_data){ |
| CXCursor PC = clang_getTypeDeclaration(PT); |
| if (clang_isInvalid(PC.kind)) |
| return false; |
| const RecordDecl *RD = |
| dyn_cast_or_null<RecordDecl>(cxcursor::getCursorDecl(PC)); |
| if (!RD || RD->isInvalidDecl()) |
| return false; |
| RD = RD->getDefinition(); |
| if (!RD || RD->isInvalidDecl()) |
| return false; |
| |
| for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); |
| I != E; ++I){ |
| const FieldDecl *FD = dyn_cast_or_null<FieldDecl>((*I)); |
| // Callback to the client. |
| switch (visitor(cxcursor::MakeCXCursor(FD, GetTU(PT)), client_data)){ |
| case CXVisit_Break: |
| return true; |
| case CXVisit_Continue: |
| break; |
| } |
| } |
| return true; |
| } |
| |
| unsigned clang_Cursor_isAnonymous(CXCursor C){ |
| if (!clang_isDeclaration(C.kind)) |
| return 0; |
| const Decl *D = cxcursor::getCursorDecl(C); |
| if (const NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(D)) { |
| return ND->isAnonymousNamespace(); |
| } else if (const TagDecl *TD = dyn_cast_or_null<TagDecl>(D)) { |
| return TD->getTypedefNameForAnonDecl() == nullptr && |
| TD->getIdentifier() == nullptr; |
| } |
| |
| return 0; |
| } |
| |
| unsigned clang_Cursor_isAnonymousRecordDecl(CXCursor C){ |
| if (!clang_isDeclaration(C.kind)) |
| return 0; |
| const Decl *D = cxcursor::getCursorDecl(C); |
| if (const RecordDecl *FD = dyn_cast_or_null<RecordDecl>(D)) |
| return FD->isAnonymousStructOrUnion(); |
| return 0; |
| } |
| |
| unsigned clang_Cursor_isInlineNamespace(CXCursor C) { |
| if (!clang_isDeclaration(C.kind)) |
| return 0; |
| const Decl *D = cxcursor::getCursorDecl(C); |
| const NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(D); |
| return ND ? ND->isInline() : 0; |
| } |
| |
| CXType clang_Type_getNamedType(CXType CT){ |
| QualType T = GetQualType(CT); |
| const Type *TP = T.getTypePtrOrNull(); |
| |
| if (TP && TP->getTypeClass() == Type::Elaborated) |
| return MakeCXType(cast<ElaboratedType>(TP)->getNamedType(), GetTU(CT)); |
| |
| return MakeCXType(QualType(), GetTU(CT)); |
| } |
| |
| unsigned clang_Type_isTransparentTagTypedef(CXType TT){ |
| QualType T = GetQualType(TT); |
| if (auto *TT = dyn_cast_or_null<TypedefType>(T.getTypePtrOrNull())) { |
| if (auto *D = TT->getDecl()) |
| return D->isTransparentTag(); |
| } |
| return false; |
| } |
| |
| enum CXTypeNullabilityKind clang_Type_getNullability(CXType CT) { |
| QualType T = GetQualType(CT); |
| if (T.isNull()) |
| return CXTypeNullability_Invalid; |
| |
| ASTContext &Ctx = cxtu::getASTUnit(GetTU(CT))->getASTContext(); |
| if (auto nullability = T->getNullability(Ctx)) { |
| switch (*nullability) { |
| case NullabilityKind::NonNull: |
| return CXTypeNullability_NonNull; |
| case NullabilityKind::Nullable: |
| return CXTypeNullability_Nullable; |
| case NullabilityKind::NullableResult: |
| return CXTypeNullability_NullableResult; |
| case NullabilityKind::Unspecified: |
| return CXTypeNullability_Unspecified; |
| } |
| } |
| return CXTypeNullability_Invalid; |
| } |
| |
| CXType clang_Type_getValueType(CXType CT) { |
| QualType T = GetQualType(CT); |
| |
| if (T.isNull() || !T->isAtomicType()) |
| return MakeCXType(QualType(), GetTU(CT)); |
| |
| const auto *AT = T->castAs<AtomicType>(); |
| return MakeCXType(AT->getValueType(), GetTU(CT)); |
| } |