//===--- 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(this)) return ATy->getElementType().getTypePtr(); // If the canonical form of this type isn't the right kind, reject it. if (!isa(CanonicalType)) { // Look through type qualifiers if (ArrayType *AT = dyn_cast(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(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(this)) return TDT->LookThroughTypedefs().getDesugaredType(); if (const TypeOfExprType *TOE = dyn_cast(this)) return TOE->getUnderlyingExpr()->getType().getDesugaredType(); if (const TypeOfType *TOT = dyn_cast(this)) return TOT->getUnderlyingType().getDesugaredType(); if (const TemplateSpecializationType *Spec = dyn_cast(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(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(CanonicalType)) return BT->getKind() == BuiltinType::Void; if (const ExtQualType *AS = dyn_cast(CanonicalType)) return AS->getBaseType()->isVoidType(); return false; } bool Type::isObjectType() const { if (isa(CanonicalType) || isa(CanonicalType) || isa(CanonicalType) || isVoidType()) return false; if (const ExtQualType *AS = dyn_cast(CanonicalType)) return AS->getBaseType()->isObjectType(); return true; } bool Type::isDerivedType() const { switch (CanonicalType->getTypeClass()) { case ExtQual: return cast(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(CanonicalType)) return CT->getElementType()->isFloatingType(); if (const ExtQualType *AS = dyn_cast(CanonicalType)) return AS->getBaseType()->isComplexType(); return false; } bool Type::isComplexIntegerType() const { // Check for GCC complex integer extension. if (const ComplexType *CT = dyn_cast(CanonicalType)) return CT->getElementType()->isIntegerType(); if (const ExtQualType *AS = dyn_cast(CanonicalType)) return AS->getBaseType()->isComplexIntegerType(); return false; } const ComplexType *Type::getAsComplexIntegerType() const { // Are we directly a complex type? if (const ComplexType *CTy = dyn_cast(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(CanonicalType)) { // Look through type qualifiers (e.g. ExtQualType's). if (isa(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(getDesugaredType()); } const BuiltinType *Type::getAsBuiltinType() const { // If this is directly a builtin type, return it. if (const BuiltinType *BTy = dyn_cast(this)) return BTy; // If the canonical form of this type isn't a builtin type, reject it. if (!isa(CanonicalType)) { // Look through type qualifiers (e.g. ExtQualType's). if (isa(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(getDesugaredType()); } const FunctionType *Type::getAsFunctionType() const { // If this is directly a function type, return it. if (const FunctionType *FTy = dyn_cast(this)) return FTy; // If the canonical form of this type isn't the right kind, reject it. if (!isa(CanonicalType)) { // Look through type qualifiers if (isa(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(getDesugaredType()); } const FunctionNoProtoType *Type::getAsFunctionNoProtoType() const { return dyn_cast_or_null(getAsFunctionType()); } const FunctionProtoType *Type::getAsFunctionProtoType() const { return dyn_cast_or_null(getAsFunctionType()); } const PointerType *Type::getAsPointerType() const { // If this is directly a pointer type, return it. if (const PointerType *PTy = dyn_cast(this)) return PTy; // If the canonical form of this type isn't the right kind, reject it. if (!isa(CanonicalType)) { // Look through type qualifiers if (isa(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(getDesugaredType()); } const BlockPointerType *Type::getAsBlockPointerType() const { // If this is directly a block pointer type, return it. if (const BlockPointerType *PTy = dyn_cast(this)) return PTy; // If the canonical form of this type isn't the right kind, reject it. if (!isa(CanonicalType)) { // Look through type qualifiers if (isa(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(getDesugaredType()); } const ReferenceType *Type::getAsReferenceType() const { // If this is directly a reference type, return it. if (const ReferenceType *RTy = dyn_cast(this)) return RTy; // If the canonical form of this type isn't the right kind, reject it. if (!isa(CanonicalType)) { // Look through type qualifiers if (isa(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(getDesugaredType()); } const LValueReferenceType *Type::getAsLValueReferenceType() const { // If this is directly an lvalue reference type, return it. if (const LValueReferenceType *RTy = dyn_cast(this)) return RTy; // If the canonical form of this type isn't the right kind, reject it. if (!isa(CanonicalType)) { // Look through type qualifiers if (isa(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(getDesugaredType()); } const RValueReferenceType *Type::getAsRValueReferenceType() const { // If this is directly an rvalue reference type, return it. if (const RValueReferenceType *RTy = dyn_cast(this)) return RTy; // If the canonical form of this type isn't the right kind, reject it. if (!isa(CanonicalType)) { // Look through type qualifiers if (isa(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(getDesugaredType()); } const MemberPointerType *Type::getAsMemberPointerType() const { // If this is directly a member pointer type, return it. if (const MemberPointerType *MTy = dyn_cast(this)) return MTy; // If the canonical form of this type isn't the right kind, reject it. if (!isa(CanonicalType)) { // Look through type qualifiers if (isa(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(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(this)) return RTy; // If the canonical form of this type isn't the right kind, reject it. if (!isa(CanonicalType)) { // Look through type qualifiers if (isa(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(getDesugaredType()); } const TagType *Type::getAsTagType() const { // If this is directly a tag type, return it. if (const TagType *TagTy = dyn_cast(this)) return TagTy; // If the canonical form of this type isn't the right kind, reject it. if (!isa(CanonicalType)) { // Look through type qualifiers if (isa(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(getDesugaredType()); } const RecordType *Type::getAsStructureType() const { // If this is directly a structure type, return it. if (const RecordType *RT = dyn_cast(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(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(getDesugaredType()); } // Look through type qualifiers if (isa(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(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(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(getDesugaredType()); } // Look through type qualifiers if (isa(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(CanonicalType.getUnqualifiedType()); } const ComplexType *Type::getAsComplexType() const { // Are we directly a complex type? if (const ComplexType *CTy = dyn_cast(this)) return CTy; // If the canonical form of this type isn't the right kind, reject it. if (!isa(CanonicalType)) { // Look through type qualifiers if (isa(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(getDesugaredType()); } const VectorType *Type::getAsVectorType() const { // Are we directly a vector type? if (const VectorType *VTy = dyn_cast(this)) return VTy; // If the canonical form of this type isn't the right kind, reject it. if (!isa(CanonicalType)) { // Look through type qualifiers if (isa(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(getDesugaredType()); } const ExtVectorType *Type::getAsExtVectorType() const { // Are we directly an OpenCU vector type? if (const ExtVectorType *VTy = dyn_cast(this)) return VTy; // If the canonical form of this type isn't the right kind, reject it. if (!isa(CanonicalType)) { // Look through type qualifiers if (isa(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(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(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(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(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(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(CanonicalType); } bool Type::isIntegerType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::Int128; if (const TagType *TT = dyn_cast(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(CanonicalType)) return true; if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isIntegerType(); if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) return EXTQT->getBaseType()->isIntegerType(); return false; } bool Type::isIntegralType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::LongLong; if (const TagType *TT = dyn_cast(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(CanonicalType)) return true; if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) return EXTQT->getBaseType()->isIntegralType(); return false; } bool Type::isEnumeralType() const { if (const TagType *TT = dyn_cast(CanonicalType)) return TT->getDecl()->isEnum(); if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) return EXTQT->getBaseType()->isEnumeralType(); return false; } bool Type::isBooleanType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::Bool; if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) return EXTQT->getBaseType()->isBooleanType(); return false; } bool Type::isCharType() const { if (const BuiltinType *BT = dyn_cast(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(CanonicalType)) return EXTQT->getBaseType()->isCharType(); return false; } bool Type::isWideCharType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) return BT->getKind() == BuiltinType::WChar; if (const ExtQualType *EXTQT = dyn_cast(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(CanonicalType)) { return BT->getKind() >= BuiltinType::Char_S && BT->getKind() <= BuiltinType::LongLong; } if (const EnumType *ET = dyn_cast(CanonicalType)) return ET->getDecl()->getIntegerType()->isSignedIntegerType(); if (const FixedWidthIntType *FWIT = dyn_cast(CanonicalType)) return FWIT->isSigned(); if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isSignedIntegerType(); if (const ExtQualType *EXTQT = dyn_cast(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(CanonicalType)) { return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::ULongLong; } if (const EnumType *ET = dyn_cast(CanonicalType)) return ET->getDecl()->getIntegerType()->isUnsignedIntegerType(); if (const FixedWidthIntType *FWIT = dyn_cast(CanonicalType)) return !FWIT->isSigned(); if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isUnsignedIntegerType(); if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) return EXTQT->getBaseType()->isUnsignedIntegerType(); return false; } bool Type::isFloatingType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Float && BT->getKind() <= BuiltinType::LongDouble; if (const ComplexType *CT = dyn_cast(CanonicalType)) return CT->getElementType()->isFloatingType(); if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isFloatingType(); if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) return EXTQT->getBaseType()->isFloatingType(); return false; } bool Type::isRealFloatingType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Float && BT->getKind() <= BuiltinType::LongDouble; if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isRealFloatingType(); if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) return EXTQT->getBaseType()->isRealFloatingType(); return false; } bool Type::isRealType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::LongDouble; if (const TagType *TT = dyn_cast(CanonicalType)) return TT->getDecl()->isEnum() && TT->getDecl()->isDefinition(); if (isa(CanonicalType)) return true; if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isRealType(); if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) return EXTQT->getBaseType()->isRealType(); return false; } bool Type::isArithmeticType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::LongDouble; if (const EnumType *ET = dyn_cast(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(CanonicalType)) return true; if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) return EXTQT->getBaseType()->isArithmeticType(); return isa(CanonicalType) || isa(CanonicalType); } bool Type::isScalarType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) return BT->getKind() != BuiltinType::Void; if (const TagType *TT = dyn_cast(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(CanonicalType)) return EXTQT->getBaseType()->isScalarType(); if (isa(CanonicalType)) return true; return isa(CanonicalType) || isa(CanonicalType) || isa(CanonicalType) || isa(CanonicalType) || isa(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(CanonicalType)) { if (CXXRecordDecl *ClassDecl = dyn_cast(Record->getDecl())) return ClassDecl->isAggregate(); return true; } if (const ExtQualType *EXTQT = dyn_cast(CanonicalType)) return EXTQT->getBaseType()->isAggregateType(); return isa(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(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(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(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(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(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(CanonicalType)->getBaseType()->isPODType(); case VariableArray: case ConstantArray: // IncompleteArray is caught by isIncompleteType() above. return cast(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(cast(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 ""; case Dependent: return ""; } } 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(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(CurType); if (TDT == 0) return QualType(CurType.getTypePtr(), TypeQuals); } } TypeOfExprType::TypeOfExprType(Expr *E, QualType can) : Type(TypeOfExpr, can, E->isTypeDependent()), TOExpr(E) { assert(!isa(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(TT->getDecl()); } bool EnumType::classof(const TagType *TT) { return isa(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(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(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(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(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(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(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 = ""; // If this is a class template specialization, print the template // arguments. if (ClassTemplateSpecializationDecl *Spec = dyn_cast(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(DC)) { if (NS->getIdentifier()) MyPart = NS->getNameAsString(); } else if (ClassTemplateSpecializationDecl *Spec = dyn_cast(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(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; }