diff options
Diffstat (limited to 'clang/lib/AST')
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 61 | ||||
-rw-r--r-- | clang/lib/AST/ASTImporter.cpp | 3 | ||||
-rw-r--r-- | clang/lib/AST/DeclObjC.cpp | 30 | ||||
-rw-r--r-- | clang/lib/AST/Expr.cpp | 10 | ||||
-rw-r--r-- | clang/lib/AST/Type.cpp | 775 | ||||
-rw-r--r-- | clang/lib/AST/TypeLoc.cpp | 11 |
6 files changed, 860 insertions, 30 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index c7a66d74897..d04121ac2f3 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -6893,9 +6893,13 @@ QualType ASTContext::areCommonBaseCompatible( const ObjCInterfaceDecl* RDecl = RHS->getInterface(); if (!LDecl || !RDecl || (declaresSameEntity(LDecl, RDecl))) return QualType(); - - do { - LHS = cast<ObjCInterfaceType>(getObjCInterfaceType(LDecl)); + + while (!declaresSameEntity(LHS->getInterface(), RDecl)) { + // Strip protocols from the left-hand side. + if (LHS->getNumProtocols() > 0) + LHS = getObjCObjectType(LHS->getBaseType(), LHS->getTypeArgsAsWritten(), + { })->castAs<ObjCObjectType>(); + if (canAssignObjCInterfaces(LHS, RHS)) { SmallVector<ObjCProtocolDecl *, 8> Protocols; getIntersectionOfProtocols(*this, Lptr, Rptr, Protocols); @@ -6906,7 +6910,13 @@ QualType ASTContext::areCommonBaseCompatible( Result = getObjCObjectPointerType(Result); return Result; } - } while ((LDecl = LDecl->getSuperClass())); + + QualType LHSSuperType = LHS->getSuperClassType(); + if (LHSSuperType.isNull()) + break; + + LHS = LHSSuperType->castAs<ObjCObjectType>(); + } return QualType(); } @@ -6918,21 +6928,15 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS, // Verify that the base decls are compatible: the RHS must be a subclass of // the LHS. - if (!LHS->getInterface()->isSuperClassOf(RHS->getInterface())) + ObjCInterfaceDecl *LHSInterface = LHS->getInterface(); + bool IsSuperClass = LHSInterface->isSuperClassOf(RHS->getInterface()); + if (!IsSuperClass) return false; - // RHS must have a superset of the protocols in the LHS. If the LHS is not - // protocol qualified at all, then we are good. - if (LHS->getNumProtocols() == 0) - return true; - - // Okay, we know the LHS has protocol qualifiers. But RHS may or may not. - // More detailed analysis is required. - // OK, if LHS is same or a superclass of RHS *and* - // this LHS, or as RHS's super class is assignment compatible with LHS. - bool IsSuperClass = - LHS->getInterface()->isSuperClassOf(RHS->getInterface()); - if (IsSuperClass) { + // If the LHS has protocol qualifiers, determine whether all of them are + // satisfied by the RHS (i.e., the RHS has a superset of the protocols in the + // LHS). + if (LHS->getNumProtocols() > 0) { // OK if conversion of LHS to SuperClass results in narrowing of types // ; i.e., SuperClass may implement at least one of the protocols // in LHS's protocol list. Example, SuperObj<P1> = lhs<P1,P2> is ok. @@ -6957,9 +6961,28 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS, if (!SuperImplementsProtocol) return false; } - return true; } - return false; + + // If the LHS is specialized, we may need to check type arguments. + if (LHS->isSpecialized()) { + // Follow the superclass chain until we've matched the LHS class in the + // hierarchy. This substitutes type arguments through. + const ObjCObjectType *RHSSuper = RHS; + while (!declaresSameEntity(RHSSuper->getInterface(), LHSInterface)) + RHSSuper = RHSSuper->getSuperClassType()->castAs<ObjCObjectType>(); + + // If the RHS is specializd, compare type arguments. + if (RHSSuper->isSpecialized()) { + ArrayRef<QualType> LHSTypeArgs = LHS->getTypeArgs(); + ArrayRef<QualType> RHSTypeArgs = RHSSuper->getTypeArgs(); + for (unsigned i = 0, n = LHSTypeArgs.size(); i != n; ++i) { + if (!hasSameType(LHSTypeArgs[i], RHSTypeArgs[i])) + return false; + } + } + } + + return true; } bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) { diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index ff80ba1ce7e..f7bfcaacd7c 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1845,7 +1845,7 @@ QualType ASTNodeImporter::VisitObjCObjectType(const ObjCObjectType *T) { return QualType(); SmallVector<QualType, 4> TypeArgs; - for (auto TypeArg : T->getTypeArgs()) { + for (auto TypeArg : T->getTypeArgsAsWritten()) { QualType ImportedTypeArg = Importer.Import(TypeArg); if (ImportedTypeArg.isNull()) return QualType(); @@ -3452,6 +3452,7 @@ Decl *ASTNodeImporter::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) { ObjCTypeParamDecl *Result = ObjCTypeParamDecl::Create( Importer.getToContext(), DC, + D->getIndex(), Importer.Import(D->getLocation()), Name.getAsIdentifierInfo(), Importer.Import(D->getColonLoc()), diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index a93c8f61336..69ff33a60aa 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -1013,6 +1013,14 @@ SourceRange ObjCMethodDecl::getReturnTypeSourceRange() const { return SourceRange(); } +QualType ObjCMethodDecl::getSendResultType(QualType receiverType) const { + // FIXME: Handle related result types here. + + return getReturnType().getNonLValueExprType(getASTContext()) + .substObjCMemberType(receiverType, getDeclContext(), + ObjCSubstitutionContext::Result); +} + static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container, const ObjCMethodDecl *Method, SmallVectorImpl<const ObjCMethodDecl *> &Methods, @@ -1190,17 +1198,18 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const { void ObjCTypeParamDecl::anchor() { } ObjCTypeParamDecl *ObjCTypeParamDecl::Create(ASTContext &ctx, DeclContext *dc, + unsigned index, SourceLocation nameLoc, IdentifierInfo *name, SourceLocation colonLoc, TypeSourceInfo *boundInfo) { - return new (ctx, dc) ObjCTypeParamDecl(ctx, dc, nameLoc, name, colonLoc, + return new (ctx, dc) ObjCTypeParamDecl(ctx, dc, index, nameLoc, name, colonLoc, boundInfo); } ObjCTypeParamDecl *ObjCTypeParamDecl::CreateDeserialized(ASTContext &ctx, unsigned ID) { - return new (ctx, ID) ObjCTypeParamDecl(ctx, nullptr, SourceLocation(), + return new (ctx, ID) ObjCTypeParamDecl(ctx, nullptr, 0, SourceLocation(), nullptr, SourceLocation(), nullptr); } @@ -1239,6 +1248,13 @@ ObjCTypeParamList *ObjCTypeParamList::create( return new (mem) ObjCTypeParamList(lAngleLoc, typeParams, rAngleLoc); } +void ObjCTypeParamList::gatherDefaultTypeArgs( + SmallVectorImpl<QualType> &typeArgs) const { + typeArgs.reserve(size()); + for (auto typeParam : *this) + typeArgs.push_back(typeParam->getUnderlyingType()); +} + //===----------------------------------------------------------------------===// // ObjCInterfaceDecl //===----------------------------------------------------------------------===// @@ -1606,6 +1622,11 @@ const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const { } } +QualType ObjCIvarDecl::getUsageType(QualType objectType) const { + return getType().substObjCMemberType(objectType, getDeclContext(), + ObjCSubstitutionContext::Property); +} + //===----------------------------------------------------------------------===// // ObjCAtDefsFieldDecl //===----------------------------------------------------------------------===// @@ -2012,6 +2033,11 @@ ObjCPropertyDecl *ObjCPropertyDecl::CreateDeserialized(ASTContext &C, QualType(), nullptr, None); } +QualType ObjCPropertyDecl::getUsageType(QualType objectType) const { + return DeclType.substObjCMemberType(objectType, getDeclContext(), + ObjCSubstitutionContext::Property); +} + //===----------------------------------------------------------------------===// // ObjCPropertyImplDecl //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 87f9ffba78e..2e066b2c42c 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -3748,6 +3748,16 @@ ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const { return nullptr; } +QualType ObjCPropertyRefExpr::getReceiverType(const ASTContext &ctx) const { + if (isClassReceiver()) + return ctx.getObjCInterfaceType(getClassReceiver()); + + if (isSuperReceiver()) + return getSuperReceiverType(); + + return getBase()->getType(); +} + StringRef ObjCBridgedCastExpr::getBridgeKindName() const { switch (getBridgeKind()) { case OBC_Bridge: diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 48245f648bb..9b2bfc0cd9e 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -491,10 +491,13 @@ bool ObjCObjectType::isSpecialized() const { if (ObjCObjectTypeBits.NumTypeArgs > 0) return true; - if (!qual_empty()) { - // Otherwise, check whether the base type is specialized. - if (auto objcObject = getBaseType()->getAs<ObjCObjectType>()) - return objcObject->isSpecialized(); + // Otherwise, check whether the base type is specialized. + if (auto objcObject = getBaseType()->getAs<ObjCObjectType>()) { + // Terminate when we reach an interface type. + if (isa<ObjCInterfaceType>(objcObject)) + return false; + + return objcObject->isSpecialized(); } // Not specialized. @@ -506,16 +509,765 @@ ArrayRef<QualType> ObjCObjectType::getTypeArgs() const { if (isSpecializedAsWritten()) return getTypeArgsAsWritten(); - if (!qual_empty()) { - // Look at the base type, which might have type arguments. - if (auto objcObject = getBaseType()->getAs<ObjCObjectType>()) - return objcObject->getTypeArgs(); + // Look at the base type, which might have type arguments. + if (auto objcObject = getBaseType()->getAs<ObjCObjectType>()) { + // Terminate when we reach an interface type. + if (isa<ObjCInterfaceType>(objcObject)) + return { }; + + return objcObject->getTypeArgs(); } // No type arguments. return { }; } +namespace { + +/// Perform a simple type transformation that does not change the +/// semantics of the type. +template<typename F> +QualType simpleTransform(ASTContext &ctx, QualType type, F &&f) { + struct Visitor : public TypeVisitor<Visitor, QualType> { + ASTContext &Ctx; + F &&TheFunc; + + QualType recurse(QualType type) { + return simpleTransform(Ctx, type, std::move(TheFunc)); + } + + public: + Visitor(ASTContext &ctx, F &&f) : Ctx(ctx), TheFunc(std::move(f)) { } + + // None of the clients of this transformation can occur where + // there are dependent types, so skip dependent types. +#define TYPE(Class, Base) +#define DEPENDENT_TYPE(Class, Base) \ + QualType Visit##Class##Type(const Class##Type *T) { return QualType(T, 0); } +#include "clang/AST/TypeNodes.def" + +#define TRIVIAL_TYPE_CLASS(Class) \ + QualType Visit##Class##Type(const Class##Type *T) { return QualType(T, 0); } + + TRIVIAL_TYPE_CLASS(Builtin) + + QualType VisitComplexType(const ComplexType *T) { + QualType elementType = recurse(T->getElementType()); + if (elementType.isNull()) + return QualType(); + + if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getComplexType(elementType); + } + + QualType VisitPointerType(const PointerType *T) { + QualType pointeeType = recurse(T->getPointeeType()); + if (pointeeType.isNull()) + return QualType(); + + if (pointeeType.getAsOpaquePtr() == T->getPointeeType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getPointerType(pointeeType); + } + + QualType VisitBlockPointerType(const BlockPointerType *T) { + QualType pointeeType = recurse(T->getPointeeType()); + if (pointeeType.isNull()) + return QualType(); + + if (pointeeType.getAsOpaquePtr() == T->getPointeeType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getBlockPointerType(pointeeType); + } + + QualType VisitLValueReferenceType(const LValueReferenceType *T) { + QualType pointeeType = recurse(T->getPointeeTypeAsWritten()); + if (pointeeType.isNull()) + return QualType(); + + if (pointeeType.getAsOpaquePtr() + == T->getPointeeTypeAsWritten().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getLValueReferenceType(pointeeType, T->isSpelledAsLValue()); + } + + QualType VisitRValueReferenceType(const RValueReferenceType *T) { + QualType pointeeType = recurse(T->getPointeeTypeAsWritten()); + if (pointeeType.isNull()) + return QualType(); + + if (pointeeType.getAsOpaquePtr() + == T->getPointeeTypeAsWritten().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getRValueReferenceType(pointeeType); + } + + QualType VisitMemberPointerType(const MemberPointerType *T) { + QualType pointeeType = recurse(T->getPointeeType()); + if (pointeeType.isNull()) + return QualType(); + + if (pointeeType.getAsOpaquePtr() == T->getPointeeType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getMemberPointerType(pointeeType, T->getClass()); + } + + QualType VisitConstantArrayType(const ConstantArrayType *T) { + QualType elementType = recurse(T->getElementType()); + if (elementType.isNull()) + return QualType(); + + if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getConstantArrayType(elementType, T->getSize(), + T->getSizeModifier(), + T->getIndexTypeCVRQualifiers()); + } + + QualType VisitVariableArrayType(const VariableArrayType *T) { + QualType elementType = recurse(T->getElementType()); + if (elementType.isNull()) + return QualType(); + + if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getVariableArrayType(elementType, T->getSizeExpr(), + T->getSizeModifier(), + T->getIndexTypeCVRQualifiers(), + T->getBracketsRange()); + } + + QualType VisitIncompleteArrayType(const IncompleteArrayType *T) { + QualType elementType = recurse(T->getElementType()); + if (elementType.isNull()) + return QualType(); + + if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getIncompleteArrayType(elementType, T->getSizeModifier(), + T->getIndexTypeCVRQualifiers()); + } + + QualType VisitVectorType(const VectorType *T) { + QualType elementType = recurse(T->getElementType()); + if (elementType.isNull()) + return QualType(); + + if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getVectorType(elementType, T->getNumElements(), + T->getVectorKind()); + } + + QualType VisitExtVectorType(const ExtVectorType *T) { + QualType elementType = recurse(T->getElementType()); + if (elementType.isNull()) + return QualType(); + + if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getExtVectorType(elementType, T->getNumElements()); + } + + QualType VisitFunctionNoProtoType(const FunctionNoProtoType *T) { + QualType returnType = recurse(T->getReturnType()); + if (returnType.isNull()) + return QualType(); + + if (returnType.getAsOpaquePtr() == T->getReturnType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getFunctionNoProtoType(returnType, T->getExtInfo()); + } + + QualType VisitFunctionProtoType(const FunctionProtoType *T) { + QualType returnType = recurse(T->getReturnType()); + if (returnType.isNull()) + return QualType(); + + // Transform parameter types. + SmallVector<QualType, 4> paramTypes; + bool paramChanged = false; + for (auto paramType : T->getParamTypes()) { + QualType newParamType = recurse(paramType); + if (newParamType.isNull()) + return QualType(); + + if (newParamType.getAsOpaquePtr() != paramType.getAsOpaquePtr()) + paramChanged = true; + + paramTypes.push_back(newParamType); + } + + // Transform extended info. + FunctionProtoType::ExtProtoInfo info = T->getExtProtoInfo(); + bool exceptionChanged = false; + if (info.ExceptionSpec.Type == EST_Dynamic) { + SmallVector<QualType, 4> exceptionTypes; + for (auto exceptionType : info.ExceptionSpec.Exceptions) { + QualType newExceptionType = recurse(exceptionType); + if (newExceptionType.isNull()) + return QualType(); + + if (newExceptionType.getAsOpaquePtr() + != exceptionType.getAsOpaquePtr()) + exceptionChanged = true; + + exceptionTypes.push_back(newExceptionType); + } + + if (exceptionChanged) { + unsigned size = sizeof(QualType) * exceptionTypes.size(); + void *mem = Ctx.Allocate(size, llvm::alignOf<QualType>()); + memcpy(mem, exceptionTypes.data(), size); + info.ExceptionSpec.Exceptions + = llvm::makeArrayRef((QualType *)mem, exceptionTypes.size()); + } + } + + if (returnType.getAsOpaquePtr() == T->getReturnType().getAsOpaquePtr() && + !paramChanged && !exceptionChanged) + return QualType(T, 0); + + return Ctx.getFunctionType(returnType, paramTypes, info); + } + + QualType VisitParenType(const ParenType *T) { + QualType innerType = recurse(T->getInnerType()); + if (innerType.isNull()) + return QualType(); + + if (innerType.getAsOpaquePtr() == T->getInnerType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getParenType(innerType); + } + + TRIVIAL_TYPE_CLASS(Typedef) + + QualType VisitAdjustedType(const AdjustedType *T) { + QualType originalType = recurse(T->getOriginalType()); + if (originalType.isNull()) + return QualType(); + + QualType adjustedType = recurse(T->getAdjustedType()); + if (adjustedType.isNull()) + return QualType(); + + if (originalType.getAsOpaquePtr() + == T->getOriginalType().getAsOpaquePtr() && + adjustedType.getAsOpaquePtr() == T->getAdjustedType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getAdjustedType(originalType, adjustedType); + } + + QualType VisitDecayedType(const DecayedType *T) { + QualType originalType = recurse(T->getOriginalType()); + if (originalType.isNull()) + return QualType(); + + if (originalType.getAsOpaquePtr() + == T->getOriginalType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getDecayedType(originalType); + } + + TRIVIAL_TYPE_CLASS(TypeOfExpr) + TRIVIAL_TYPE_CLASS(TypeOf) + TRIVIAL_TYPE_CLASS(Decltype) + TRIVIAL_TYPE_CLASS(UnaryTransform) + TRIVIAL_TYPE_CLASS(Record) + TRIVIAL_TYPE_CLASS(Enum) + + // FIXME: Non-trivial to implement, but important for C++ + TRIVIAL_TYPE_CLASS(Elaborated) + + QualType VisitAttributedType(const AttributedType *T) { + QualType modifiedType = recurse(T->getModifiedType()); + if (modifiedType.isNull()) + return QualType(); + + QualType equivalentType = recurse(T->getEquivalentType()); + if (equivalentType.isNull()) + return QualType(); + + if (modifiedType.getAsOpaquePtr() + == T->getModifiedType().getAsOpaquePtr() && + equivalentType.getAsOpaquePtr() + == T->getEquivalentType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getAttributedType(T->getAttrKind(), modifiedType, + equivalentType); + } + + QualType VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) { + QualType replacementType = recurse(T->getReplacementType()); + if (replacementType.isNull()) + return QualType(); + + if (replacementType.getAsOpaquePtr() + == T->getReplacementType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getSubstTemplateTypeParmType(T->getReplacedParameter(), + replacementType); + } + + // FIXME: Non-trivial to implement, but important for C++ + TRIVIAL_TYPE_CLASS(TemplateSpecialization) + + QualType VisitAutoType(const AutoType *T) { + if (!T->isDeduced()) + return QualType(T, 0); + + QualType deducedType = recurse(T->getDeducedType()); + if (deducedType.isNull()) + return QualType(); + + if (deducedType.getAsOpaquePtr() + == T->getDeducedType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getAutoType(deducedType, T->isDecltypeAuto(), + T->isDependentType()); + } + + // FIXME: Non-trivial to implement, but important for C++ + TRIVIAL_TYPE_CLASS(PackExpansion) + + QualType VisitObjCObjectType(const ObjCObjectType *T) { + QualType baseType = recurse(T->getBaseType()); + if (baseType.isNull()) + return QualType(); + + // Transform type arguments. + bool typeArgChanged = false; + SmallVector<QualType, 4> typeArgs; + for (auto typeArg : T->getTypeArgsAsWritten()) { + QualType newTypeArg = recurse(typeArg); + if (newTypeArg.isNull()) + return QualType(); + + if (newTypeArg.getAsOpaquePtr() != typeArg.getAsOpaquePtr()) + typeArgChanged = true; + + typeArgs.push_back(newTypeArg); + } + + if (baseType.getAsOpaquePtr() == T->getBaseType().getAsOpaquePtr() && + !typeArgChanged) + return QualType(T, 0); + + return Ctx.getObjCObjectType(baseType, typeArgs, + llvm::makeArrayRef(T->qual_begin(), + T->getNumProtocols())); + } + + TRIVIAL_TYPE_CLASS(ObjCInterface) + + QualType VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { + QualType pointeeType = recurse(T->getPointeeType()); + if (pointeeType.isNull()) + return QualType(); + + if (pointeeType.getAsOpaquePtr() + == T->getPointeeType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getObjCObjectPointerType(pointeeType); + } + + QualType VisitAtomicType(const AtomicType *T) { + QualType valueType = recurse(T->getValueType()); + if (valueType.isNull()) + return QualType(); + + if (valueType.getAsOpaquePtr() + == T->getValueType().getAsOpaquePtr()) + return QualType(T, 0); + + return Ctx.getAtomicType(valueType); + } + +#undef TRIVIAL_TYPE_CLASS + }; + + // Transform the type. If it changed, return the transformed result. + QualType transformed = f(type); + if (transformed.getAsOpaquePtr() != type.getAsOpaquePtr()) + return transformed; + + // Split out the qualifiers from the type. + SplitQualType splitType = type.split(); + + // Visit the type itself. + Visitor visitor(ctx, std::move(f)); + QualType result = visitor.Visit(splitType.Ty); + if (result.isNull()) + return result; + + // Reconstruct the transformed type by applying the local qualifiers + // from the split type. + return ctx.getQualifiedType(result, splitType.Quals); +} + +} // end anonymous namespace + +/// Substitute the given type arguments for Objective-C type +/// parameters within the given type, recursively. +QualType QualType::substObjCTypeArgs( + ASTContext &ctx, + ArrayRef<QualType> typeArgs, + ObjCSubstitutionContext context) const { + return simpleTransform(ctx, *this, + [&](QualType type) -> QualType { + SplitQualType splitType = type.split(); + + // Replace an Objective-C type parameter reference with the corresponding + // type argument. + if (const auto *typedefTy = dyn_cast<TypedefType>(splitType.Ty)) { + if (auto *typeParam = dyn_cast<ObjCTypeParamDecl>(typedefTy->getDecl())) { + // If we have type arguments, use them. + if (!typeArgs.empty()) { + // FIXME: Introduce SubstObjCTypeParamType ? + QualType argType = typeArgs[typeParam->getIndex()]; + return ctx.getQualifiedType(argType, splitType.Quals); + } + + switch (context) { + case ObjCSubstitutionContext::Ordinary: + case ObjCSubstitutionContext::Parameter: + case ObjCSubstitutionContext::Superclass: + // Substitute the bound. + return ctx.getQualifiedType(typeParam->getUnderlyingType(), + splitType.Quals); + + case ObjCSubstitutionContext::Result: + case ObjCSubstitutionContext::Property: + // Substitute 'id' or 'Class', as appropriate. + + // If the underlying type is based on 'Class', substitute 'Class'. + if (typeParam->getUnderlyingType()->isObjCClassType() || + typeParam->getUnderlyingType()->isObjCQualifiedClassType()) { + return ctx.getQualifiedType(ctx.getObjCClassType(), + splitType.Quals); + } + + // Otherwise, substitute 'id'. + return ctx.getQualifiedType(ctx.getObjCIdType(), splitType.Quals); + } + } + } + + // If we have a function type, update the context appropriately. + if (const auto *funcType = dyn_cast<FunctionType>(splitType.Ty)) { + // Substitute result type. + QualType returnType = funcType->getReturnType().substObjCTypeArgs( + ctx, + typeArgs, + ObjCSubstitutionContext::Result); + if (returnType.isNull()) + return QualType(); + + // Handle non-prototyped functions, which only substitute into the result + // type. + if (isa<FunctionNoProtoType>(funcType)) { + // If the return type was unchanged, do nothing. + if (returnType.getAsOpaquePtr() + == funcType->getReturnType().getAsOpaquePtr()) + return type; + + // Otherwise, build a new type. + return ctx.getFunctionNoProtoType(returnType, funcType->getExtInfo()); + } + + const auto *funcProtoType = cast<FunctionProtoType>(funcType); + + // Transform parameter types. + SmallVector<QualType, 4> paramTypes; + bool paramChanged = false; + for (auto paramType : funcProtoType->getParamTypes()) { + QualType newParamType = paramType.substObjCTypeArgs( + ctx, + typeArgs, + ObjCSubstitutionContext::Parameter); + if (newParamType.isNull()) + return QualType(); + + if (newParamType.getAsOpaquePtr() != paramType.getAsOpaquePtr()) + paramChanged = true; + + paramTypes.push_back(newParamType); + } + + // Transform extended info. + FunctionProtoType::ExtProtoInfo info = funcProtoType->getExtProtoInfo(); + bool exceptionChanged = false; + if (info.ExceptionSpec.Type == EST_Dynamic) { + SmallVector<QualType, 4> exceptionTypes; + for (auto exceptionType : info.ExceptionSpec.Exceptions) { + QualType newExceptionType = exceptionType.substObjCTypeArgs( + ctx, + typeArgs, + ObjCSubstitutionContext::Ordinary); + if (newExceptionType.isNull()) + return QualType(); + + if (newExceptionType.getAsOpaquePtr() + != exceptionType.getAsOpaquePtr()) + exceptionChanged = true; + + exceptionTypes.push_back(newExceptionType); + } + + if (exceptionChanged) { + unsigned size = sizeof(QualType) * exceptionTypes.size(); + void *mem = ctx.Allocate(size, llvm::alignOf<QualType>()); + memcpy(mem, exceptionTypes.data(), size); + info.ExceptionSpec.Exceptions + = llvm::makeArrayRef((QualType *)mem, exceptionTypes.size()); + } + } + + if (returnType.getAsOpaquePtr() + == funcProtoType->getReturnType().getAsOpaquePtr() && + !paramChanged && !exceptionChanged) + return type; + + return ctx.getFunctionType(returnType, paramTypes, info); + } + + // Substitute into the type arguments of a specialized Objective-C object + // type. + if (const auto *objcObjectType = dyn_cast<ObjCObjectType>(splitType.Ty)) { + if (objcObjectType->isSpecializedAsWritten()) { + SmallVector<QualType, 4> newTypeArgs; + bool anyChanged = false; + for (auto typeArg : objcObjectType->getTypeArgsAsWritten()) { + QualType newTypeArg = typeArg.substObjCTypeArgs( + ctx, typeArgs, + ObjCSubstitutionContext::Ordinary); + if (newTypeArg.isNull()) + return QualType(); + + if (newTypeArg.getAsOpaquePtr() != typeArg.getAsOpaquePtr()) { + // If we're substituting based on an unspecialized context type, + // produce an unspecialized type. + ArrayRef<ObjCProtocolDecl *> protocols( + objcObjectType->qual_begin(), + objcObjectType->getNumProtocols()); + if (typeArgs.empty() && + context != ObjCSubstitutionContext::Superclass) { + return ctx.getObjCObjectType(objcObjectType->getBaseType(), { }, + protocols); + } + + anyChanged = true; + } + + newTypeArgs.push_back(newTypeArg); + } + + if (anyChanged) { + ArrayRef<ObjCProtocolDecl *> protocols( + objcObjectType->qual_begin(), + objcObjectType->getNumProtocols()); + return ctx.getObjCObjectType(objcObjectType->getBaseType(), + newTypeArgs, protocols); + } + } + + return type; + } + + return type; + }); +} + +QualType QualType::substObjCMemberType(QualType objectType, + const DeclContext *dc, + ObjCSubstitutionContext context) const { + if (auto subs = objectType->getObjCSubstitutions(dc)) + return substObjCTypeArgs(dc->getParentASTContext(), *subs, context); + + return *this; +} + +Optional<ArrayRef<QualType>> Type::getObjCSubstitutions( + const DeclContext *dc) const { + // Look through method scopes. + if (auto method = dyn_cast<ObjCMethodDecl>(dc)) + dc = method->getDeclContext(); + + // Find the class or category in which the type we're substituting + // was declared. + const ObjCInterfaceDecl *dcClassDecl = dyn_cast<ObjCInterfaceDecl>(dc); + const ObjCCategoryDecl *dcCategoryDecl = nullptr; + ObjCTypeParamList *dcTypeParams = nullptr; + if (dcClassDecl) { + // If the class does not have any type parameters, there's no + // substitution to do. + dcTypeParams = dcClassDecl->getTypeParamList(); + if (!dcTypeParams) + return None; + } else { + // If we are in neither a class mor a category, there's no + // substitution to perform. + dcCategoryDecl = dyn_cast<ObjCCategoryDecl>(dc); + if (!dcCategoryDecl) + return None; + + // If the category does not have any type parameters, there's no + // substitution to do. + dcTypeParams = dcCategoryDecl->getTypeParamList(); + if (!dcTypeParams) + return None; + + dcClassDecl = dcCategoryDecl->getClassInterface(); + if (!dcClassDecl) + return None; + } + assert(dcTypeParams && "No substitutions to perform"); + assert(dcClassDecl && "No class context"); + + // Find the underlying object type. + const ObjCObjectType *objectType; + if (const auto *objectPointerType = getAs<ObjCObjectPointerType>()) { + objectType = objectPointerType->getObjectType(); + } else if (getAs<BlockPointerType>()) { + ASTContext &ctx = dc->getParentASTContext(); + objectType = ctx.getObjCObjectType(ctx.ObjCBuiltinIdTy, { }, { }) + ->castAs<ObjCObjectType>();; + } else { + objectType = getAs<ObjCObjectType>(); + } + + /// Extract the class from the receiver object type. + ObjCInterfaceDecl *curClassDecl = objectType ? objectType->getInterface() + : nullptr; + if (!curClassDecl) { + // If we don't have a context type (e.g., this is "id" or some + // variant thereof), substitute the bounds. + return llvm::ArrayRef<QualType>(); + } + + // Follow the superclass chain until we've mapped the receiver type + // to the same class as the context. + while (curClassDecl != dcClassDecl) { + // Map to the superclass type. + QualType superType = objectType->getSuperClassType(); + if (superType.isNull()) { + objectType = nullptr; + break; + } + + objectType = superType->castAs<ObjCObjectType>(); + curClassDecl = objectType->getInterface(); + } + + // If we don't have a receiver type, or the receiver type does not + // have type arguments, substitute in the defaults. + if (!objectType || objectType->isUnspecialized()) { + return llvm::ArrayRef<QualType>(); + } + + // The receiver type has the type arguments we want. + return objectType->getTypeArgs(); +} + +void ObjCObjectType::computeSuperClassTypeSlow() const { + // Retrieve the class declaration for this type. If there isn't one + // (e.g., this is some variant of "id" or "Class"), then there is no + // superclass type. + ObjCInterfaceDecl *classDecl = getInterface(); + if (!classDecl) { + CachedSuperClassType.setInt(true); + return; + } + + // Extract the superclass type. + const ObjCObjectType *superClassObjTy = classDecl->getSuperClassType(); + if (!superClassObjTy) { + CachedSuperClassType.setInt(true); + return; + } + + ObjCInterfaceDecl *superClassDecl = superClassObjTy->getInterface(); + if (!superClassDecl) { + CachedSuperClassType.setInt(true); + return; + } + + // If the superclass doesn't have type parameters, then there is no + // substitution to perform. + QualType superClassType(superClassObjTy, 0); + ObjCTypeParamList *superClassTypeParams = superClassDecl->getTypeParamList(); + if (!superClassTypeParams) { + CachedSuperClassType.setPointerAndInt( + superClassType->castAs<ObjCObjectType>(), true); + return; + } + + // If the superclass reference is unspecialized, return it. + if (superClassObjTy->isUnspecialized()) { + CachedSuperClassType.setPointerAndInt(superClassObjTy, true); + return; + } + + // If the subclass is not parameterized, there aren't any type + // parameters in the superclass reference to substitute. + ObjCTypeParamList *typeParams = classDecl->getTypeParamList(); + if (!typeParams) { + CachedSuperClassType.setPointerAndInt( + superClassType->castAs<ObjCObjectType>(), true); + return; + } + + // If the subclass type isn't specialized, return the unspecialized + // superclass. + if (isUnspecialized()) { + QualType unspecializedSuper + = classDecl->getASTContext().getObjCInterfaceType( + superClassObjTy->getInterface()); + CachedSuperClassType.setPointerAndInt( + unspecializedSuper->castAs<ObjCObjectType>(), + true); + return; + } + + // Substitute the provided type arguments into the superclass type. + ArrayRef<QualType> typeArgs = getTypeArgs(); + assert(typeArgs.size() == typeParams->size()); + CachedSuperClassType.setPointerAndInt( + superClassType.substObjCTypeArgs(classDecl->getASTContext(), typeArgs, + ObjCSubstitutionContext::Superclass) + ->castAs<ObjCObjectType>(), + true); +} + +QualType ObjCObjectPointerType::getSuperClassType() const { + QualType superObjectType = getObjectType()->getSuperClassType(); + if (superObjectType.isNull()) + return superObjectType; + + ASTContext &ctx = getInterfaceDecl()->getASTContext(); + return ctx.getObjCObjectPointerType(superObjectType); +} const ObjCObjectType *Type::getAsObjCQualifiedInterfaceType() const { // There is no sugar for ObjCObjectType's, just return the canonical @@ -551,6 +1303,13 @@ const ObjCObjectPointerType *Type::getAsObjCQualifiedClassType() const { return nullptr; } +const ObjCObjectType *Type::getAsObjCInterfaceType() const { + if (const ObjCObjectType *OT = getAs<ObjCObjectType>()) { + if (OT->getInterface()) + return OT; + } + return nullptr; +} const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const { if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) { if (OPT->getInterfaceType()) diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp index 0d497aad8e4..02d0cec708c 100644 --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -312,6 +312,17 @@ TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) { return TL; } +SourceLocation TypeLoc::findNullabilityLoc() const { + if (auto attributedLoc = getAs<AttributedTypeLoc>()) { + if (attributedLoc.getAttrKind() == AttributedType::attr_nullable || + attributedLoc.getAttrKind() == AttributedType::attr_nonnull || + attributedLoc.getAttrKind() == AttributedType::attr_null_unspecified) + return attributedLoc.getAttrNameLoc(); + } + + return SourceLocation(); +} + void ObjCObjectTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) { setHasBaseTypeAsWritten(true); |