summaryrefslogtreecommitdiffstats
path: root/lib/AST/Type.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/AST/Type.cpp')
-rw-r--r--lib/AST/Type.cpp1658
1 files changed, 1658 insertions, 0 deletions
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
new file mode 100644
index 0000000..b2ee58f
--- /dev/null
+++ b/lib/AST/Type.cpp
@@ -0,0 +1,1658 @@
+//===--- Type.cpp - Type representation and manipulation ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements type-related functionality.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+bool QualType::isConstant(ASTContext &Ctx) const {
+ if (isConstQualified())
+ return true;
+
+ if (getTypePtr()->isArrayType())
+ return Ctx.getAsArrayType(*this)->getElementType().isConstant(Ctx);
+
+ return false;
+}
+
+void Type::Destroy(ASTContext& C) {
+ this->~Type();
+ C.Deallocate(this);
+}
+
+void VariableArrayType::Destroy(ASTContext& C) {
+ if (SizeExpr)
+ SizeExpr->Destroy(C);
+ this->~VariableArrayType();
+ C.Deallocate(this);
+}
+
+void DependentSizedArrayType::Destroy(ASTContext& C) {
+ SizeExpr->Destroy(C);
+ this->~DependentSizedArrayType();
+ C.Deallocate(this);
+}
+
+/// getArrayElementTypeNoTypeQual - If this is an array type, return the
+/// element type of the array, potentially with type qualifiers missing.
+/// This method should never be used when type qualifiers are meaningful.
+const Type *Type::getArrayElementTypeNoTypeQual() const {
+ // If this is directly an array type, return it.
+ if (const ArrayType *ATy = dyn_cast<ArrayType>(this))
+ return ATy->getElementType().getTypePtr();
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<ArrayType>(CanonicalType)) {
+ // Look through type qualifiers
+ if (ArrayType *AT = dyn_cast<ArrayType>(CanonicalType.getUnqualifiedType()))
+ return AT->getElementType().getTypePtr();
+ return 0;
+ }
+
+ // If this is a typedef for an array type, strip the typedef off without
+ // losing all typedef information.
+ return cast<ArrayType>(getDesugaredType())->getElementType().getTypePtr();
+}
+
+/// getDesugaredType - Return the specified type with any "sugar" removed from
+/// the type. This takes off typedefs, typeof's etc. If the outer level of
+/// the type is already concrete, it returns it unmodified. This is similar
+/// to getting the canonical type, but it doesn't remove *all* typedefs. For
+/// example, it returns "T*" as "T*", (not as "int*"), because the pointer is
+/// concrete.
+///
+/// \param ForDisplay When true, the desugaring is provided for
+/// display purposes only. In this case, we apply more heuristics to
+/// decide whether it is worth providing a desugared form of the type
+/// or not.
+QualType QualType::getDesugaredType(bool ForDisplay) const {
+ return getTypePtr()->getDesugaredType(ForDisplay)
+ .getWithAdditionalQualifiers(getCVRQualifiers());
+}
+
+/// getDesugaredType - Return the specified type with any "sugar" removed from
+/// type type. This takes off typedefs, typeof's etc. If the outer level of
+/// the type is already concrete, it returns it unmodified. This is similar
+/// to getting the canonical type, but it doesn't remove *all* typedefs. For
+/// example, it return "T*" as "T*", (not as "int*"), because the pointer is
+/// concrete.
+///
+/// \param ForDisplay When true, the desugaring is provided for
+/// display purposes only. In this case, we apply more heuristics to
+/// decide whether it is worth providing a desugared form of the type
+/// or not.
+QualType Type::getDesugaredType(bool ForDisplay) const {
+ if (const TypedefType *TDT = dyn_cast<TypedefType>(this))
+ return TDT->LookThroughTypedefs().getDesugaredType();
+ if (const TypeOfExprType *TOE = dyn_cast<TypeOfExprType>(this))
+ return TOE->getUnderlyingExpr()->getType().getDesugaredType();
+ if (const TypeOfType *TOT = dyn_cast<TypeOfType>(this))
+ return TOT->getUnderlyingType().getDesugaredType();
+ if (const TemplateSpecializationType *Spec
+ = dyn_cast<TemplateSpecializationType>(this)) {
+ if (ForDisplay)
+ return QualType(this, 0);
+
+ QualType Canon = Spec->getCanonicalTypeInternal();
+ if (Canon->getAsTemplateSpecializationType())
+ return QualType(this, 0);
+ return Canon->getDesugaredType();
+ }
+ if (const QualifiedNameType *QualName = dyn_cast<QualifiedNameType>(this)) {
+ if (ForDisplay) {
+ // If desugaring the type that the qualified name is referring to
+ // produces something interesting, that's our desugared type.
+ QualType NamedType = QualName->getNamedType().getDesugaredType();
+ if (NamedType != QualName->getNamedType())
+ return NamedType;
+ } else
+ return QualName->getNamedType().getDesugaredType();
+ }
+
+ return QualType(this, 0);
+}
+
+/// isVoidType - Helper method to determine if this is the 'void' type.
+bool Type::isVoidType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() == BuiltinType::Void;
+ if (const ExtQualType *AS = dyn_cast<ExtQualType>(CanonicalType))
+ return AS->getBaseType()->isVoidType();
+ return false;
+}
+
+bool Type::isObjectType() const {
+ if (isa<FunctionType>(CanonicalType) || isa<ReferenceType>(CanonicalType) ||
+ isa<IncompleteArrayType>(CanonicalType) || isVoidType())
+ return false;
+ if (const ExtQualType *AS = dyn_cast<ExtQualType>(CanonicalType))
+ return AS->getBaseType()->isObjectType();
+ return true;
+}
+
+bool Type::isDerivedType() const {
+ switch (CanonicalType->getTypeClass()) {
+ case ExtQual:
+ return cast<ExtQualType>(CanonicalType)->getBaseType()->isDerivedType();
+ case Pointer:
+ case VariableArray:
+ case ConstantArray:
+ case IncompleteArray:
+ case FunctionProto:
+ case FunctionNoProto:
+ case LValueReference:
+ case RValueReference:
+ case Record:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool Type::isClassType() const {
+ if (const RecordType *RT = getAsRecordType())
+ return RT->getDecl()->isClass();
+ return false;
+}
+bool Type::isStructureType() const {
+ if (const RecordType *RT = getAsRecordType())
+ return RT->getDecl()->isStruct();
+ return false;
+}
+bool Type::isUnionType() const {
+ if (const RecordType *RT = getAsRecordType())
+ return RT->getDecl()->isUnion();
+ return false;
+}
+
+bool Type::isComplexType() const {
+ if (const ComplexType *CT = dyn_cast<ComplexType>(CanonicalType))
+ return CT->getElementType()->isFloatingType();
+ if (const ExtQualType *AS = dyn_cast<ExtQualType>(CanonicalType))
+ return AS->getBaseType()->isComplexType();
+ return false;
+}
+
+bool Type::isComplexIntegerType() const {
+ // Check for GCC complex integer extension.
+ if (const ComplexType *CT = dyn_cast<ComplexType>(CanonicalType))
+ return CT->getElementType()->isIntegerType();
+ if (const ExtQualType *AS = dyn_cast<ExtQualType>(CanonicalType))
+ return AS->getBaseType()->isComplexIntegerType();
+ return false;
+}
+
+const ComplexType *Type::getAsComplexIntegerType() const {
+ // Are we directly a complex type?
+ if (const ComplexType *CTy = dyn_cast<ComplexType>(this)) {
+ if (CTy->getElementType()->isIntegerType())
+ return CTy;
+ return 0;
+ }
+
+ // If the canonical form of this type isn't what we want, reject it.
+ if (!isa<ComplexType>(CanonicalType)) {
+ // Look through type qualifiers (e.g. ExtQualType's).
+ if (isa<ComplexType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsComplexIntegerType();
+ return 0;
+ }
+
+ // If this is a typedef for a complex type, strip the typedef off without
+ // losing all typedef information.
+ return cast<ComplexType>(getDesugaredType());
+}
+
+const BuiltinType *Type::getAsBuiltinType() const {
+ // If this is directly a builtin type, return it.
+ if (const BuiltinType *BTy = dyn_cast<BuiltinType>(this))
+ return BTy;
+
+ // If the canonical form of this type isn't a builtin type, reject it.
+ if (!isa<BuiltinType>(CanonicalType)) {
+ // Look through type qualifiers (e.g. ExtQualType's).
+ if (isa<BuiltinType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsBuiltinType();
+ return 0;
+ }
+
+ // If this is a typedef for a builtin type, strip the typedef off without
+ // losing all typedef information.
+ return cast<BuiltinType>(getDesugaredType());
+}
+
+const FunctionType *Type::getAsFunctionType() const {
+ // If this is directly a function type, return it.
+ if (const FunctionType *FTy = dyn_cast<FunctionType>(this))
+ return FTy;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<FunctionType>(CanonicalType)) {
+ // Look through type qualifiers
+ if (isa<FunctionType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsFunctionType();
+ return 0;
+ }
+
+ // If this is a typedef for a function type, strip the typedef off without
+ // losing all typedef information.
+ return cast<FunctionType>(getDesugaredType());
+}
+
+const FunctionNoProtoType *Type::getAsFunctionNoProtoType() const {
+ return dyn_cast_or_null<FunctionNoProtoType>(getAsFunctionType());
+}
+
+const FunctionProtoType *Type::getAsFunctionProtoType() const {
+ return dyn_cast_or_null<FunctionProtoType>(getAsFunctionType());
+}
+
+
+const PointerType *Type::getAsPointerType() const {
+ // If this is directly a pointer type, return it.
+ if (const PointerType *PTy = dyn_cast<PointerType>(this))
+ return PTy;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<PointerType>(CanonicalType)) {
+ // Look through type qualifiers
+ if (isa<PointerType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsPointerType();
+ return 0;
+ }
+
+ // If this is a typedef for a pointer type, strip the typedef off without
+ // losing all typedef information.
+ return cast<PointerType>(getDesugaredType());
+}
+
+const BlockPointerType *Type::getAsBlockPointerType() const {
+ // If this is directly a block pointer type, return it.
+ if (const BlockPointerType *PTy = dyn_cast<BlockPointerType>(this))
+ return PTy;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<BlockPointerType>(CanonicalType)) {
+ // Look through type qualifiers
+ if (isa<BlockPointerType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsBlockPointerType();
+ return 0;
+ }
+
+ // If this is a typedef for a block pointer type, strip the typedef off
+ // without losing all typedef information.
+ return cast<BlockPointerType>(getDesugaredType());
+}
+
+const ReferenceType *Type::getAsReferenceType() const {
+ // If this is directly a reference type, return it.
+ if (const ReferenceType *RTy = dyn_cast<ReferenceType>(this))
+ return RTy;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<ReferenceType>(CanonicalType)) {
+ // Look through type qualifiers
+ if (isa<ReferenceType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsReferenceType();
+ return 0;
+ }
+
+ // If this is a typedef for a reference type, strip the typedef off without
+ // losing all typedef information.
+ return cast<ReferenceType>(getDesugaredType());
+}
+
+const LValueReferenceType *Type::getAsLValueReferenceType() const {
+ // If this is directly an lvalue reference type, return it.
+ if (const LValueReferenceType *RTy = dyn_cast<LValueReferenceType>(this))
+ return RTy;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<LValueReferenceType>(CanonicalType)) {
+ // Look through type qualifiers
+ if (isa<LValueReferenceType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsLValueReferenceType();
+ return 0;
+ }
+
+ // If this is a typedef for an lvalue reference type, strip the typedef off
+ // without losing all typedef information.
+ return cast<LValueReferenceType>(getDesugaredType());
+}
+
+const RValueReferenceType *Type::getAsRValueReferenceType() const {
+ // If this is directly an rvalue reference type, return it.
+ if (const RValueReferenceType *RTy = dyn_cast<RValueReferenceType>(this))
+ return RTy;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<RValueReferenceType>(CanonicalType)) {
+ // Look through type qualifiers
+ if (isa<RValueReferenceType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsRValueReferenceType();
+ return 0;
+ }
+
+ // If this is a typedef for an rvalue reference type, strip the typedef off
+ // without losing all typedef information.
+ return cast<RValueReferenceType>(getDesugaredType());
+}
+
+const MemberPointerType *Type::getAsMemberPointerType() const {
+ // If this is directly a member pointer type, return it.
+ if (const MemberPointerType *MTy = dyn_cast<MemberPointerType>(this))
+ return MTy;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<MemberPointerType>(CanonicalType)) {
+ // Look through type qualifiers
+ if (isa<MemberPointerType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsMemberPointerType();
+ return 0;
+ }
+
+ // If this is a typedef for a member pointer type, strip the typedef off
+ // without losing all typedef information.
+ return cast<MemberPointerType>(getDesugaredType());
+}
+
+/// isVariablyModifiedType (C99 6.7.5p3) - Return true for variable length
+/// array types and types that contain variable array types in their
+/// declarator
+bool Type::isVariablyModifiedType() const {
+ // A VLA is a variably modified type.
+ if (isVariableArrayType())
+ return true;
+
+ // An array can contain a variably modified type
+ if (const Type *T = getArrayElementTypeNoTypeQual())
+ return T->isVariablyModifiedType();
+
+ // A pointer can point to a variably modified type.
+ // Also, C++ references and member pointers can point to a variably modified
+ // type, where VLAs appear as an extension to C++, and should be treated
+ // correctly.
+ if (const PointerType *PT = getAsPointerType())
+ return PT->getPointeeType()->isVariablyModifiedType();
+ if (const ReferenceType *RT = getAsReferenceType())
+ return RT->getPointeeType()->isVariablyModifiedType();
+ if (const MemberPointerType *PT = getAsMemberPointerType())
+ return PT->getPointeeType()->isVariablyModifiedType();
+
+ // A function can return a variably modified type
+ // This one isn't completely obvious, but it follows from the
+ // definition in C99 6.7.5p3. Because of this rule, it's
+ // illegal to declare a function returning a variably modified type.
+ if (const FunctionType *FT = getAsFunctionType())
+ return FT->getResultType()->isVariablyModifiedType();
+
+ return false;
+}
+
+const RecordType *Type::getAsRecordType() const {
+ // If this is directly a record type, return it.
+ if (const RecordType *RTy = dyn_cast<RecordType>(this))
+ return RTy;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<RecordType>(CanonicalType)) {
+ // Look through type qualifiers
+ if (isa<RecordType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsRecordType();
+ return 0;
+ }
+
+ // If this is a typedef for a record type, strip the typedef off without
+ // losing all typedef information.
+ return cast<RecordType>(getDesugaredType());
+}
+
+const TagType *Type::getAsTagType() const {
+ // If this is directly a tag type, return it.
+ if (const TagType *TagTy = dyn_cast<TagType>(this))
+ return TagTy;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<TagType>(CanonicalType)) {
+ // Look through type qualifiers
+ if (isa<TagType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsTagType();
+ return 0;
+ }
+
+ // If this is a typedef for a tag type, strip the typedef off without
+ // losing all typedef information.
+ return cast<TagType>(getDesugaredType());
+}
+
+const RecordType *Type::getAsStructureType() const {
+ // If this is directly a structure type, return it.
+ if (const RecordType *RT = dyn_cast<RecordType>(this)) {
+ if (RT->getDecl()->isStruct())
+ return RT;
+ }
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (const RecordType *RT = dyn_cast<RecordType>(CanonicalType)) {
+ if (!RT->getDecl()->isStruct())
+ return 0;
+
+ // If this is a typedef for a structure type, strip the typedef off without
+ // losing all typedef information.
+ return cast<RecordType>(getDesugaredType());
+ }
+ // Look through type qualifiers
+ if (isa<RecordType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsStructureType();
+ return 0;
+}
+
+const RecordType *Type::getAsUnionType() const {
+ // If this is directly a union type, return it.
+ if (const RecordType *RT = dyn_cast<RecordType>(this)) {
+ if (RT->getDecl()->isUnion())
+ return RT;
+ }
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (const RecordType *RT = dyn_cast<RecordType>(CanonicalType)) {
+ if (!RT->getDecl()->isUnion())
+ return 0;
+
+ // If this is a typedef for a union type, strip the typedef off without
+ // losing all typedef information.
+ return cast<RecordType>(getDesugaredType());
+ }
+
+ // Look through type qualifiers
+ if (isa<RecordType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsUnionType();
+ return 0;
+}
+
+const EnumType *Type::getAsEnumType() const {
+ // Check the canonicalized unqualified type directly; the more complex
+ // version is unnecessary because there isn't any typedef information
+ // to preserve.
+ return dyn_cast<EnumType>(CanonicalType.getUnqualifiedType());
+}
+
+const ComplexType *Type::getAsComplexType() const {
+ // Are we directly a complex type?
+ if (const ComplexType *CTy = dyn_cast<ComplexType>(this))
+ return CTy;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<ComplexType>(CanonicalType)) {
+ // Look through type qualifiers
+ if (isa<ComplexType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsComplexType();
+ return 0;
+ }
+
+ // If this is a typedef for a complex type, strip the typedef off without
+ // losing all typedef information.
+ return cast<ComplexType>(getDesugaredType());
+}
+
+const VectorType *Type::getAsVectorType() const {
+ // Are we directly a vector type?
+ if (const VectorType *VTy = dyn_cast<VectorType>(this))
+ return VTy;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<VectorType>(CanonicalType)) {
+ // Look through type qualifiers
+ if (isa<VectorType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsVectorType();
+ return 0;
+ }
+
+ // If this is a typedef for a vector type, strip the typedef off without
+ // losing all typedef information.
+ return cast<VectorType>(getDesugaredType());
+}
+
+const ExtVectorType *Type::getAsExtVectorType() const {
+ // Are we directly an OpenCU vector type?
+ if (const ExtVectorType *VTy = dyn_cast<ExtVectorType>(this))
+ return VTy;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<ExtVectorType>(CanonicalType)) {
+ // Look through type qualifiers
+ if (isa<ExtVectorType>(CanonicalType.getUnqualifiedType()))
+ return CanonicalType.getUnqualifiedType()->getAsExtVectorType();
+ return 0;
+ }
+
+ // If this is a typedef for an extended vector type, strip the typedef off
+ // without losing all typedef information.
+ return cast<ExtVectorType>(getDesugaredType());
+}
+
+const ObjCInterfaceType *Type::getAsObjCInterfaceType() const {
+ // There is no sugar for ObjCInterfaceType's, just return the canonical
+ // type pointer if it is the right class. There is no typedef information to
+ // return and these cannot be Address-space qualified.
+ return dyn_cast<ObjCInterfaceType>(CanonicalType.getUnqualifiedType());
+}
+
+const ObjCQualifiedInterfaceType *
+Type::getAsObjCQualifiedInterfaceType() const {
+ // There is no sugar for ObjCQualifiedInterfaceType's, just return the
+ // canonical type pointer if it is the right class.
+ return dyn_cast<ObjCQualifiedInterfaceType>(CanonicalType.getUnqualifiedType());
+}
+
+const ObjCQualifiedIdType *Type::getAsObjCQualifiedIdType() const {
+ // There is no sugar for ObjCQualifiedIdType's, just return the canonical
+ // type pointer if it is the right class.
+ return dyn_cast<ObjCQualifiedIdType>(CanonicalType.getUnqualifiedType());
+}
+
+const TemplateTypeParmType *Type::getAsTemplateTypeParmType() const {
+ // There is no sugar for template type parameters, so just return
+ // the canonical type pointer if it is the right class.
+ // FIXME: can these be address-space qualified?
+ return dyn_cast<TemplateTypeParmType>(CanonicalType);
+}
+
+const TemplateSpecializationType *
+Type::getAsTemplateSpecializationType() const {
+ // There is no sugar for class template specialization types, so
+ // just return the canonical type pointer if it is the right class.
+ return dyn_cast<TemplateSpecializationType>(CanonicalType);
+}
+
+bool Type::isIntegerType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() >= BuiltinType::Bool &&
+ BT->getKind() <= BuiltinType::Int128;
+ if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
+ // Incomplete enum types are not treated as integer types.
+ // FIXME: In C++, enum types are never integer types.
+ if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition())
+ return true;
+ if (isa<FixedWidthIntType>(CanonicalType))
+ return true;
+ if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
+ return VT->getElementType()->isIntegerType();
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isIntegerType();
+ return false;
+}
+
+bool Type::isIntegralType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() >= BuiltinType::Bool &&
+ BT->getKind() <= BuiltinType::LongLong;
+ if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
+ if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition())
+ return true; // Complete enum types are integral.
+ // FIXME: In C++, enum types are never integral.
+ if (isa<FixedWidthIntType>(CanonicalType))
+ return true;
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isIntegralType();
+ return false;
+}
+
+bool Type::isEnumeralType() const {
+ if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
+ return TT->getDecl()->isEnum();
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isEnumeralType();
+ return false;
+}
+
+bool Type::isBooleanType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() == BuiltinType::Bool;
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isBooleanType();
+ return false;
+}
+
+bool Type::isCharType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() == BuiltinType::Char_U ||
+ BT->getKind() == BuiltinType::UChar ||
+ BT->getKind() == BuiltinType::Char_S ||
+ BT->getKind() == BuiltinType::SChar;
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isCharType();
+ return false;
+}
+
+bool Type::isWideCharType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() == BuiltinType::WChar;
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isWideCharType();
+ return false;
+}
+
+/// isSignedIntegerType - Return true if this is an integer type that is
+/// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..],
+/// an enum decl which has a signed representation, or a vector of signed
+/// integer element type.
+bool Type::isSignedIntegerType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) {
+ return BT->getKind() >= BuiltinType::Char_S &&
+ BT->getKind() <= BuiltinType::LongLong;
+ }
+
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
+ return ET->getDecl()->getIntegerType()->isSignedIntegerType();
+
+ if (const FixedWidthIntType *FWIT =
+ dyn_cast<FixedWidthIntType>(CanonicalType))
+ return FWIT->isSigned();
+
+ if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
+ return VT->getElementType()->isSignedIntegerType();
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isSignedIntegerType();
+ return false;
+}
+
+/// isUnsignedIntegerType - Return true if this is an integer type that is
+/// unsigned, according to C99 6.2.5p6 [which returns true for _Bool], an enum
+/// decl which has an unsigned representation, or a vector of unsigned integer
+/// element type.
+bool Type::isUnsignedIntegerType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) {
+ return BT->getKind() >= BuiltinType::Bool &&
+ BT->getKind() <= BuiltinType::ULongLong;
+ }
+
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
+ return ET->getDecl()->getIntegerType()->isUnsignedIntegerType();
+
+ if (const FixedWidthIntType *FWIT =
+ dyn_cast<FixedWidthIntType>(CanonicalType))
+ return !FWIT->isSigned();
+
+ if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
+ return VT->getElementType()->isUnsignedIntegerType();
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isUnsignedIntegerType();
+ return false;
+}
+
+bool Type::isFloatingType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() >= BuiltinType::Float &&
+ BT->getKind() <= BuiltinType::LongDouble;
+ if (const ComplexType *CT = dyn_cast<ComplexType>(CanonicalType))
+ return CT->getElementType()->isFloatingType();
+ if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
+ return VT->getElementType()->isFloatingType();
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isFloatingType();
+ return false;
+}
+
+bool Type::isRealFloatingType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() >= BuiltinType::Float &&
+ BT->getKind() <= BuiltinType::LongDouble;
+ if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
+ return VT->getElementType()->isRealFloatingType();
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isRealFloatingType();
+ return false;
+}
+
+bool Type::isRealType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() >= BuiltinType::Bool &&
+ BT->getKind() <= BuiltinType::LongDouble;
+ if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
+ return TT->getDecl()->isEnum() && TT->getDecl()->isDefinition();
+ if (isa<FixedWidthIntType>(CanonicalType))
+ return true;
+ if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
+ return VT->getElementType()->isRealType();
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isRealType();
+ return false;
+}
+
+bool Type::isArithmeticType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() >= BuiltinType::Bool &&
+ BT->getKind() <= BuiltinType::LongDouble;
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
+ // GCC allows forward declaration of enum types (forbid by C99 6.7.2.3p2).
+ // If a body isn't seen by the time we get here, return false.
+ return ET->getDecl()->isDefinition();
+ if (isa<FixedWidthIntType>(CanonicalType))
+ return true;
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isArithmeticType();
+ return isa<ComplexType>(CanonicalType) || isa<VectorType>(CanonicalType);
+}
+
+bool Type::isScalarType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() != BuiltinType::Void;
+ if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) {
+ // Enums are scalar types, but only if they are defined. Incomplete enums
+ // are not treated as scalar types.
+ if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition())
+ return true;
+ return false;
+ }
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isScalarType();
+ if (isa<FixedWidthIntType>(CanonicalType))
+ return true;
+ return isa<PointerType>(CanonicalType) ||
+ isa<BlockPointerType>(CanonicalType) ||
+ isa<MemberPointerType>(CanonicalType) ||
+ isa<ComplexType>(CanonicalType) ||
+ isa<ObjCQualifiedIdType>(CanonicalType);
+}
+
+/// \brief Determines whether the type is a C++ aggregate type or C
+/// aggregate or union type.
+///
+/// An aggregate type is an array or a class type (struct, union, or
+/// class) that has no user-declared constructors, no private or
+/// protected non-static data members, no base classes, and no virtual
+/// functions (C++ [dcl.init.aggr]p1). The notion of an aggregate type
+/// subsumes the notion of C aggregates (C99 6.2.5p21) because it also
+/// includes union types.
+bool Type::isAggregateType() const {
+ if (const RecordType *Record = dyn_cast<RecordType>(CanonicalType)) {
+ if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(Record->getDecl()))
+ return ClassDecl->isAggregate();
+
+ return true;
+ }
+
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isAggregateType();
+ return isa<ArrayType>(CanonicalType);
+}
+
+/// isConstantSizeType - Return true if this is not a variable sized type,
+/// according to the rules of C99 6.7.5p3. It is not legal to call this on
+/// incomplete types or dependent types.
+bool Type::isConstantSizeType() const {
+ if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType))
+ return EXTQT->getBaseType()->isConstantSizeType();
+ assert(!isIncompleteType() && "This doesn't make sense for incomplete types");
+ assert(!isDependentType() && "This doesn't make sense for dependent types");
+ // The VAT must have a size, as it is known to be complete.
+ return !isa<VariableArrayType>(CanonicalType);
+}
+
+/// isIncompleteType - Return true if this is an incomplete type (C99 6.2.5p1)
+/// - a type that can describe objects, but which lacks information needed to
+/// determine its size.
+bool Type::isIncompleteType() const {
+ switch (CanonicalType->getTypeClass()) {
+ default: return false;
+ case ExtQual:
+ return cast<ExtQualType>(CanonicalType)->getBaseType()->isIncompleteType();
+ case Builtin:
+ // Void is the only incomplete builtin type. Per C99 6.2.5p19, it can never
+ // be completed.
+ return isVoidType();
+ case Record:
+ case Enum:
+ // A tagged type (struct/union/enum/class) is incomplete if the decl is a
+ // forward declaration, but not a full definition (C99 6.2.5p22).
+ return !cast<TagType>(CanonicalType)->getDecl()->isDefinition();
+ case IncompleteArray:
+ // An array of unknown size is an incomplete type (C99 6.2.5p22).
+ return true;
+ case ObjCInterface:
+ case ObjCQualifiedInterface:
+ // ObjC interfaces are incomplete if they are @class, not @interface.
+ return cast<ObjCInterfaceType>(this)->getDecl()->isForwardDecl();
+ }
+}
+
+/// isPODType - Return true if this is a plain-old-data type (C++ 3.9p10)
+bool Type::isPODType() const {
+ // The compiler shouldn't query this for incomplete types, but the user might.
+ // We return false for that case.
+ if (isIncompleteType())
+ return false;
+
+ switch (CanonicalType->getTypeClass()) {
+ // Everything not explicitly mentioned is not POD.
+ default: return false;
+ case ExtQual:
+ return cast<ExtQualType>(CanonicalType)->getBaseType()->isPODType();
+ case VariableArray:
+ case ConstantArray:
+ // IncompleteArray is caught by isIncompleteType() above.
+ return cast<ArrayType>(CanonicalType)->getElementType()->isPODType();
+
+ case Builtin:
+ case Complex:
+ case Pointer:
+ case MemberPointer:
+ case Vector:
+ case ExtVector:
+ case ObjCQualifiedId:
+ return true;
+
+ case Enum:
+ return true;
+
+ case Record:
+ if (CXXRecordDecl *ClassDecl
+ = dyn_cast<CXXRecordDecl>(cast<RecordType>(CanonicalType)->getDecl()))
+ return ClassDecl->isPOD();
+
+ // C struct/union is POD.
+ return true;
+ }
+}
+
+bool Type::isPromotableIntegerType() const {
+ if (const BuiltinType *BT = getAsBuiltinType())
+ switch (BT->getKind()) {
+ case BuiltinType::Bool:
+ case BuiltinType::Char_S:
+ case BuiltinType::Char_U:
+ case BuiltinType::SChar:
+ case BuiltinType::UChar:
+ case BuiltinType::Short:
+ case BuiltinType::UShort:
+ return true;
+ default:
+ return false;
+ }
+ return false;
+}
+
+bool Type::isNullPtrType() const {
+ if (const BuiltinType *BT = getAsBuiltinType())
+ return BT->getKind() == BuiltinType::NullPtr;
+ return false;
+}
+
+bool Type::isSpecifierType() const {
+ // Note that this intentionally does not use the canonical type.
+ switch (getTypeClass()) {
+ case Builtin:
+ case Record:
+ case Enum:
+ case Typedef:
+ case Complex:
+ case TypeOfExpr:
+ case TypeOf:
+ case TemplateTypeParm:
+ case TemplateSpecialization:
+ case QualifiedName:
+ case Typename:
+ case ObjCInterface:
+ case ObjCQualifiedInterface:
+ case ObjCQualifiedId:
+ return true;
+ default:
+ return false;
+ }
+}
+
+const char *BuiltinType::getName(bool CPlusPlus) const {
+ switch (getKind()) {
+ default: assert(0 && "Unknown builtin type!");
+ case Void: return "void";
+ case Bool: return CPlusPlus? "bool" : "_Bool";
+ case Char_S: return "char";
+ case Char_U: return "char";
+ case SChar: return "signed char";
+ case Short: return "short";
+ case Int: return "int";
+ case Long: return "long";
+ case LongLong: return "long long";
+ case Int128: return "__int128_t";
+ case UChar: return "unsigned char";
+ case UShort: return "unsigned short";
+ case UInt: return "unsigned int";
+ case ULong: return "unsigned long";
+ case ULongLong: return "unsigned long long";
+ case UInt128: return "__uint128_t";
+ case Float: return "float";
+ case Double: return "double";
+ case LongDouble: return "long double";
+ case WChar: return "wchar_t";
+ case NullPtr: return "nullptr_t";
+ case Overload: return "<overloaded function type>";
+ case Dependent: return "<dependent type>";
+ }
+}
+
+void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
+ arg_type_iterator ArgTys,
+ unsigned NumArgs, bool isVariadic,
+ unsigned TypeQuals, bool hasExceptionSpec,
+ bool anyExceptionSpec, unsigned NumExceptions,
+ exception_iterator Exs) {
+ ID.AddPointer(Result.getAsOpaquePtr());
+ for (unsigned i = 0; i != NumArgs; ++i)
+ ID.AddPointer(ArgTys[i].getAsOpaquePtr());
+ ID.AddInteger(isVariadic);
+ ID.AddInteger(TypeQuals);
+ ID.AddInteger(hasExceptionSpec);
+ if (hasExceptionSpec) {
+ ID.AddInteger(anyExceptionSpec);
+ for(unsigned i = 0; i != NumExceptions; ++i)
+ ID.AddPointer(Exs[i].getAsOpaquePtr());
+ }
+}
+
+void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic(),
+ getTypeQuals(), hasExceptionSpec(), hasAnyExceptionSpec(),
+ getNumExceptions(), exception_begin());
+}
+
+void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID,
+ const ObjCInterfaceDecl *Decl,
+ ObjCProtocolDecl **protocols,
+ unsigned NumProtocols) {
+ ID.AddPointer(Decl);
+ for (unsigned i = 0; i != NumProtocols; i++)
+ ID.AddPointer(protocols[i]);
+}
+
+void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getDecl(), &Protocols[0], getNumProtocols());
+}
+
+void ObjCQualifiedIdType::Profile(llvm::FoldingSetNodeID &ID,
+ ObjCProtocolDecl **protocols,
+ unsigned NumProtocols) {
+ for (unsigned i = 0; i != NumProtocols; i++)
+ ID.AddPointer(protocols[i]);
+}
+
+void ObjCQualifiedIdType::Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, &Protocols[0], getNumProtocols());
+}
+
+/// LookThroughTypedefs - Return the ultimate type this typedef corresponds to
+/// potentially looking through *all* consequtive typedefs. This returns the
+/// sum of the type qualifiers, so if you have:
+/// typedef const int A;
+/// typedef volatile A B;
+/// looking through the typedefs for B will give you "const volatile A".
+///
+QualType TypedefType::LookThroughTypedefs() const {
+ // Usually, there is only a single level of typedefs, be fast in that case.
+ QualType FirstType = getDecl()->getUnderlyingType();
+ if (!isa<TypedefType>(FirstType))
+ return FirstType;
+
+ // Otherwise, do the fully general loop.
+ unsigned TypeQuals = 0;
+ const TypedefType *TDT = this;
+ while (1) {
+ QualType CurType = TDT->getDecl()->getUnderlyingType();
+
+
+ /// FIXME:
+ /// FIXME: This is incorrect for ExtQuals!
+ /// FIXME:
+ TypeQuals |= CurType.getCVRQualifiers();
+
+ TDT = dyn_cast<TypedefType>(CurType);
+ if (TDT == 0)
+ return QualType(CurType.getTypePtr(), TypeQuals);
+ }
+}
+
+TypeOfExprType::TypeOfExprType(Expr *E, QualType can)
+ : Type(TypeOfExpr, can, E->isTypeDependent()), TOExpr(E) {
+ assert(!isa<TypedefType>(can) && "Invalid canonical type");
+}
+
+TagType::TagType(TypeClass TC, TagDecl *D, QualType can)
+ : Type(TC, can, D->isDependentType()), decl(D, 0) {}
+
+bool RecordType::classof(const TagType *TT) {
+ return isa<RecordDecl>(TT->getDecl());
+}
+
+bool EnumType::classof(const TagType *TT) {
+ return isa<EnumDecl>(TT->getDecl());
+}
+
+bool
+TemplateSpecializationType::
+anyDependentTemplateArguments(const TemplateArgument *Args, unsigned NumArgs) {
+ for (unsigned Idx = 0; Idx < NumArgs; ++Idx) {
+ switch (Args[Idx].getKind()) {
+ case TemplateArgument::Type:
+ if (Args[Idx].getAsType()->isDependentType())
+ return true;
+ break;
+
+ case TemplateArgument::Declaration:
+ case TemplateArgument::Integral:
+ // Never dependent
+ break;
+
+ case TemplateArgument::Expression:
+ if (Args[Idx].getAsExpr()->isTypeDependent() ||
+ Args[Idx].getAsExpr()->isValueDependent())
+ return true;
+ break;
+ }
+ }
+
+ return false;
+}
+
+TemplateSpecializationType::
+TemplateSpecializationType(TemplateName T, const TemplateArgument *Args,
+ unsigned NumArgs, QualType Canon)
+ : Type(TemplateSpecialization,
+ Canon.isNull()? QualType(this, 0) : Canon,
+ T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)),
+ Template(T), NumArgs(NumArgs)
+{
+ assert((!Canon.isNull() ||
+ T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)) &&
+ "No canonical type for non-dependent class template specialization");
+
+ TemplateArgument *TemplateArgs
+ = reinterpret_cast<TemplateArgument *>(this + 1);
+ for (unsigned Arg = 0; Arg < NumArgs; ++Arg)
+ new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]);
+}
+
+void TemplateSpecializationType::Destroy(ASTContext& C) {
+ for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
+ // FIXME: Not all expressions get cloned, so we can't yet perform
+ // this destruction.
+ // if (Expr *E = getArg(Arg).getAsExpr())
+ // E->Destroy(C);
+ }
+}
+
+TemplateSpecializationType::iterator
+TemplateSpecializationType::end() const {
+ return begin() + getNumArgs();
+}
+
+const TemplateArgument &
+TemplateSpecializationType::getArg(unsigned Idx) const {
+ assert(Idx < getNumArgs() && "Template argument out of range");
+ return getArgs()[Idx];
+}
+
+void
+TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
+ TemplateName T,
+ const TemplateArgument *Args,
+ unsigned NumArgs) {
+ T.Profile(ID);
+ for (unsigned Idx = 0; Idx < NumArgs; ++Idx)
+ Args[Idx].Profile(ID);
+}
+
+//===----------------------------------------------------------------------===//
+// Type Printing
+//===----------------------------------------------------------------------===//
+
+void QualType::dump(const char *msg) const {
+ PrintingPolicy Policy;
+ std::string R = "identifier";
+ getAsStringInternal(R, Policy);
+ if (msg)
+ fprintf(stderr, "%s: %s\n", msg, R.c_str());
+ else
+ fprintf(stderr, "%s\n", R.c_str());
+}
+void QualType::dump() const {
+ dump("");
+}
+
+void Type::dump() const {
+ std::string S = "identifier";
+ getAsStringInternal(S, PrintingPolicy());
+ fprintf(stderr, "%s\n", S.c_str());
+}
+
+
+
+static void AppendTypeQualList(std::string &S, unsigned TypeQuals) {
+ // Note: funkiness to ensure we get a space only between quals.
+ bool NonePrinted = true;
+ if (TypeQuals & QualType::Const)
+ S += "const", NonePrinted = false;
+ if (TypeQuals & QualType::Volatile)
+ S += (NonePrinted+" volatile"), NonePrinted = false;
+ if (TypeQuals & QualType::Restrict)
+ S += (NonePrinted+" restrict"), NonePrinted = false;
+}
+
+std::string QualType::getAsString() const {
+ std::string S;
+ getAsStringInternal(S, PrintingPolicy());
+ return S;
+}
+
+void
+QualType::getAsStringInternal(std::string &S,
+ const PrintingPolicy &Policy) const {
+ if (isNull()) {
+ S += "NULL TYPE";
+ return;
+ }
+
+ if (Policy.SuppressSpecifiers && getTypePtr()->isSpecifierType())
+ return;
+
+ // Print qualifiers as appropriate.
+ if (unsigned Tq = getCVRQualifiers()) {
+ std::string TQS;
+ AppendTypeQualList(TQS, Tq);
+ if (!S.empty())
+ S = TQS + ' ' + S;
+ else
+ S = TQS;
+ }
+
+ getTypePtr()->getAsStringInternal(S, Policy);
+}
+
+void BuiltinType::getAsStringInternal(std::string &S,
+ const PrintingPolicy &Policy) const {
+ if (S.empty()) {
+ S = getName(Policy.CPlusPlus);
+ } else {
+ // Prefix the basic type, e.g. 'int X'.
+ S = ' ' + S;
+ S = getName(Policy.CPlusPlus) + S;
+ }
+}
+
+void FixedWidthIntType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ // FIXME: Once we get bitwidth attribute, write as
+ // "int __attribute__((bitwidth(x)))".
+ std::string prefix = "__clang_fixedwidth";
+ prefix += llvm::utostr_32(Width);
+ prefix += (char)(Signed ? 'S' : 'U');
+ if (S.empty()) {
+ S = prefix;
+ } else {
+ // Prefix the basic type, e.g. 'int X'.
+ S = prefix + S;
+ }
+}
+
+
+void ComplexType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ ElementType->getAsStringInternal(S, Policy);
+ S = "_Complex " + S;
+}
+
+void ExtQualType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ bool NeedsSpace = false;
+ if (AddressSpace) {
+ S = "__attribute__((address_space("+llvm::utostr_32(AddressSpace)+")))" + S;
+ NeedsSpace = true;
+ }
+ if (GCAttrType != QualType::GCNone) {
+ if (NeedsSpace)
+ S += ' ';
+ S += "__attribute__((objc_gc(";
+ if (GCAttrType == QualType::Weak)
+ S += "weak";
+ else
+ S += "strong";
+ S += ")))";
+ }
+ BaseType->getAsStringInternal(S, Policy);
+}
+
+void PointerType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ S = '*' + S;
+
+ // Handle things like 'int (*A)[4];' correctly.
+ // FIXME: this should include vectors, but vectors use attributes I guess.
+ if (isa<ArrayType>(getPointeeType()))
+ S = '(' + S + ')';
+
+ getPointeeType().getAsStringInternal(S, Policy);
+}
+
+void BlockPointerType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ S = '^' + S;
+ PointeeType.getAsStringInternal(S, Policy);
+}
+
+void LValueReferenceType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ S = '&' + S;
+
+ // Handle things like 'int (&A)[4];' correctly.
+ // FIXME: this should include vectors, but vectors use attributes I guess.
+ if (isa<ArrayType>(getPointeeType()))
+ S = '(' + S + ')';
+
+ getPointeeType().getAsStringInternal(S, Policy);
+}
+
+void RValueReferenceType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ S = "&&" + S;
+
+ // Handle things like 'int (&&A)[4];' correctly.
+ // FIXME: this should include vectors, but vectors use attributes I guess.
+ if (isa<ArrayType>(getPointeeType()))
+ S = '(' + S + ')';
+
+ getPointeeType().getAsStringInternal(S, Policy);
+}
+
+void MemberPointerType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ std::string C;
+ Class->getAsStringInternal(C, Policy);
+ C += "::*";
+ S = C + S;
+
+ // Handle things like 'int (Cls::*A)[4];' correctly.
+ // FIXME: this should include vectors, but vectors use attributes I guess.
+ if (isa<ArrayType>(getPointeeType()))
+ S = '(' + S + ')';
+
+ getPointeeType().getAsStringInternal(S, Policy);
+}
+
+void ConstantArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ S += '[';
+ S += llvm::utostr(getSize().getZExtValue());
+ S += ']';
+
+ getElementType().getAsStringInternal(S, Policy);
+}
+
+void IncompleteArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ S += "[]";
+
+ getElementType().getAsStringInternal(S, Policy);
+}
+
+void VariableArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ S += '[';
+
+ if (getIndexTypeQualifier()) {
+ AppendTypeQualList(S, getIndexTypeQualifier());
+ S += ' ';
+ }
+
+ if (getSizeModifier() == Static)
+ S += "static";
+ else if (getSizeModifier() == Star)
+ S += '*';
+
+ if (getSizeExpr()) {
+ std::string SStr;
+ llvm::raw_string_ostream s(SStr);
+ getSizeExpr()->printPretty(s, 0, Policy);
+ S += s.str();
+ }
+ S += ']';
+
+ getElementType().getAsStringInternal(S, Policy);
+}
+
+void DependentSizedArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ S += '[';
+
+ if (getIndexTypeQualifier()) {
+ AppendTypeQualList(S, getIndexTypeQualifier());
+ S += ' ';
+ }
+
+ if (getSizeModifier() == Static)
+ S += "static";
+ else if (getSizeModifier() == Star)
+ S += '*';
+
+ if (getSizeExpr()) {
+ std::string SStr;
+ llvm::raw_string_ostream s(SStr);
+ getSizeExpr()->printPretty(s, 0, Policy);
+ S += s.str();
+ }
+ S += ']';
+
+ getElementType().getAsStringInternal(S, Policy);
+}
+
+void VectorType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ // FIXME: We prefer to print the size directly here, but have no way
+ // to get the size of the type.
+ S += " __attribute__((__vector_size__(";
+ S += llvm::utostr_32(NumElements); // convert back to bytes.
+ S += " * sizeof(" + ElementType.getAsString() + "))))";
+ ElementType.getAsStringInternal(S, Policy);
+}
+
+void ExtVectorType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ S += " __attribute__((ext_vector_type(";
+ S += llvm::utostr_32(NumElements);
+ S += ")))";
+ ElementType.getAsStringInternal(S, Policy);
+}
+
+void TypeOfExprType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
+ if (!InnerString.empty()) // Prefix the basic type, e.g. 'typeof(e) X'.
+ InnerString = ' ' + InnerString;
+ std::string Str;
+ llvm::raw_string_ostream s(Str);
+ getUnderlyingExpr()->printPretty(s, 0, Policy);
+ InnerString = "typeof " + s.str() + InnerString;
+}
+
+void TypeOfType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
+ if (!InnerString.empty()) // Prefix the basic type, e.g. 'typeof(t) X'.
+ InnerString = ' ' + InnerString;
+ std::string Tmp;
+ getUnderlyingType().getAsStringInternal(Tmp, Policy);
+ InnerString = "typeof(" + Tmp + ")" + InnerString;
+}
+
+void FunctionNoProtoType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ // If needed for precedence reasons, wrap the inner part in grouping parens.
+ if (!S.empty())
+ S = "(" + S + ")";
+
+ S += "()";
+ getResultType().getAsStringInternal(S, Policy);
+}
+
+void FunctionProtoType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
+ // If needed for precedence reasons, wrap the inner part in grouping parens.
+ if (!S.empty())
+ S = "(" + S + ")";
+
+ S += "(";
+ std::string Tmp;
+ PrintingPolicy ParamPolicy(Policy);
+ ParamPolicy.SuppressSpecifiers = false;
+ for (unsigned i = 0, e = getNumArgs(); i != e; ++i) {
+ if (i) S += ", ";
+ getArgType(i).getAsStringInternal(Tmp, ParamPolicy);
+ S += Tmp;
+ Tmp.clear();
+ }
+
+ if (isVariadic()) {
+ if (getNumArgs())
+ S += ", ";
+ S += "...";
+ } else if (getNumArgs() == 0) {
+ // Do not emit int() if we have a proto, emit 'int(void)'.
+ S += "void";
+ }
+
+ S += ")";
+ getResultType().getAsStringInternal(S, Policy);
+}
+
+
+void TypedefType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
+ if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
+ InnerString = ' ' + InnerString;
+ InnerString = getDecl()->getIdentifier()->getName() + InnerString;
+}
+
+void TemplateTypeParmType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
+ if (!InnerString.empty()) // Prefix the basic type, e.g. 'parmname X'.
+ InnerString = ' ' + InnerString;
+
+ if (!Name)
+ InnerString = "type-parameter-" + llvm::utostr_32(Depth) + '-' +
+ llvm::utostr_32(Index) + InnerString;
+ else
+ InnerString = Name->getName() + InnerString;
+}
+
+std::string
+TemplateSpecializationType::PrintTemplateArgumentList(
+ const TemplateArgument *Args,
+ unsigned NumArgs,
+ const PrintingPolicy &Policy) {
+ std::string SpecString;
+ SpecString += '<';
+ for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
+ if (Arg)
+ SpecString += ", ";
+
+ // Print the argument into a string.
+ std::string ArgString;
+ switch (Args[Arg].getKind()) {
+ case TemplateArgument::Type:
+ Args[Arg].getAsType().getAsStringInternal(ArgString, Policy);
+ break;
+
+ case TemplateArgument::Declaration:
+ ArgString = cast<NamedDecl>(Args[Arg].getAsDecl())->getNameAsString();
+ break;
+
+ case TemplateArgument::Integral:
+ ArgString = Args[Arg].getAsIntegral()->toString(10, true);
+ break;
+
+ case TemplateArgument::Expression: {
+ llvm::raw_string_ostream s(ArgString);
+ Args[Arg].getAsExpr()->printPretty(s, 0, Policy);
+ break;
+ }
+ }
+
+ // If this is the first argument and its string representation
+ // begins with the global scope specifier ('::foo'), add a space
+ // to avoid printing the diagraph '<:'.
+ if (!Arg && !ArgString.empty() && ArgString[0] == ':')
+ SpecString += ' ';
+
+ SpecString += ArgString;
+ }
+
+ // If the last character of our string is '>', add another space to
+ // keep the two '>''s separate tokens. We don't *have* to do this in
+ // C++0x, but it's still good hygiene.
+ if (SpecString[SpecString.size() - 1] == '>')
+ SpecString += ' ';
+
+ SpecString += '>';
+
+ return SpecString;
+}
+
+void
+TemplateSpecializationType::
+getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
+ std::string SpecString;
+
+ {
+ llvm::raw_string_ostream OS(SpecString);
+ Template.print(OS, Policy);
+ }
+
+ SpecString += PrintTemplateArgumentList(getArgs(), getNumArgs(), Policy);
+ if (InnerString.empty())
+ InnerString.swap(SpecString);
+ else
+ InnerString = SpecString + ' ' + InnerString;
+}
+
+void QualifiedNameType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
+ std::string MyString;
+
+ {
+ llvm::raw_string_ostream OS(MyString);
+ NNS->print(OS, Policy);
+ }
+
+ std::string TypeStr;
+ PrintingPolicy InnerPolicy(Policy);
+ InnerPolicy.SuppressTagKind = true;
+ NamedType.getAsStringInternal(TypeStr, InnerPolicy);
+
+ MyString += TypeStr;
+ if (InnerString.empty())
+ InnerString.swap(MyString);
+ else
+ InnerString = MyString + ' ' + InnerString;
+}
+
+void TypenameType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
+ std::string MyString;
+
+ {
+ llvm::raw_string_ostream OS(MyString);
+ OS << "typename ";
+ NNS->print(OS, Policy);
+
+ if (const IdentifierInfo *Ident = getIdentifier())
+ OS << Ident->getName();
+ else if (const TemplateSpecializationType *Spec = getTemplateId()) {
+ Spec->getTemplateName().print(OS, Policy, true);
+ OS << TemplateSpecializationType::PrintTemplateArgumentList(
+ Spec->getArgs(),
+ Spec->getNumArgs(),
+ Policy);
+ }
+ }
+
+ if (InnerString.empty())
+ InnerString.swap(MyString);
+ else
+ InnerString = MyString + ' ' + InnerString;
+}
+
+void ObjCInterfaceType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
+ if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
+ InnerString = ' ' + InnerString;
+ InnerString = getDecl()->getIdentifier()->getName() + InnerString;
+}
+
+void
+ObjCQualifiedInterfaceType::getAsStringInternal(std::string &InnerString,
+ const PrintingPolicy &Policy) const {
+ if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
+ InnerString = ' ' + InnerString;
+ std::string ObjCQIString = getDecl()->getNameAsString();
+ ObjCQIString += '<';
+ bool isFirst = true;
+ for (qual_iterator I = qual_begin(), E = qual_end(); I != E; ++I) {
+ if (isFirst)
+ isFirst = false;
+ else
+ ObjCQIString += ',';
+ ObjCQIString += (*I)->getNameAsString();
+ }
+ ObjCQIString += '>';
+ InnerString = ObjCQIString + InnerString;
+}
+
+void ObjCQualifiedIdType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
+ if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
+ InnerString = ' ' + InnerString;
+ std::string ObjCQIString = "id";
+ ObjCQIString += '<';
+ for (qual_iterator I = qual_begin(), E = qual_end(); I != E; ++I) {
+ ObjCQIString += (*I)->getNameAsString();
+ if (I+1 != E)
+ ObjCQIString += ',';
+ }
+ ObjCQIString += '>';
+ InnerString = ObjCQIString + InnerString;
+}
+
+void TagType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
+ if (Policy.SuppressTag)
+ return;
+
+ if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
+ InnerString = ' ' + InnerString;
+
+ const char *Kind = Policy.SuppressTagKind? 0 : getDecl()->getKindName();
+ const char *ID;
+ if (const IdentifierInfo *II = getDecl()->getIdentifier())
+ ID = II->getName();
+ else if (TypedefDecl *Typedef = getDecl()->getTypedefForAnonDecl()) {
+ Kind = 0;
+ assert(Typedef->getIdentifier() && "Typedef without identifier?");
+ ID = Typedef->getIdentifier()->getName();
+ } else
+ ID = "<anonymous>";
+
+ // If this is a class template specialization, print the template
+ // arguments.
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(getDecl())) {
+ const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
+ std::string TemplateArgsStr
+ = TemplateSpecializationType::PrintTemplateArgumentList(
+ TemplateArgs.getFlatArgumentList(),
+ TemplateArgs.flat_size(),
+ Policy);
+ InnerString = TemplateArgsStr + InnerString;
+ }
+
+ if (Kind) {
+ // Compute the full nested-name-specifier for this type. In C,
+ // this will always be empty.
+ std::string ContextStr;
+ for (DeclContext *DC = getDecl()->getDeclContext();
+ !DC->isTranslationUnit(); DC = DC->getParent()) {
+ std::string MyPart;
+ if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) {
+ if (NS->getIdentifier())
+ MyPart = NS->getNameAsString();
+ } else if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(DC)) {
+ const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
+ std::string TemplateArgsStr
+ = TemplateSpecializationType::PrintTemplateArgumentList(
+ TemplateArgs.getFlatArgumentList(),
+ TemplateArgs.flat_size(),
+ Policy);
+ MyPart = Spec->getIdentifier()->getName() + TemplateArgsStr;
+ } else if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) {
+ if (TypedefDecl *Typedef = Tag->getTypedefForAnonDecl())
+ MyPart = Typedef->getIdentifier()->getName();
+ else if (Tag->getIdentifier())
+ MyPart = Tag->getIdentifier()->getName();
+ }
+
+ if (!MyPart.empty())
+ ContextStr = MyPart + "::" + ContextStr;
+ }
+
+ InnerString = std::string(Kind) + " " + ContextStr + ID + InnerString;
+ } else
+ InnerString = ID + InnerString;
+}
OpenPOWER on IntegriCloud